KaiOS设备图片上传遇网络错误:FormData与Base64方案排查
KaiOS设备图片上传问题解决方案
问题描述
在KaiOS设备开发应用的图片上传功能时,尝试Base64和FormData两种方式均失败,报错:
Network error when attempting to fetch resources
仅纯文本POST请求可正常工作,两种方案在桌面/移动浏览器中均无问题,仅KaiOS设备出现异常。
尝试过的代码
1. Base64上传方式
const handleCreatePost = async () => { // Convert all images to base64 const base64Images = await Promise.all( postData?.files?.map((file) => blobToBase64(file)) ); createPost( { content: postData.postContent, files: base64Images.map((img, i) => ({ originalname: postData.files[i].name, mimetype: postData.files[i].type, data: img, size: postData.files[i].size, })), }, { onSuccess: () => { toast.success("Post created successfully"); router.push(ALL_LINKS.EXPLORE_FEED.pageLink); }, onError: () => { toast.error("Failed to create post"); }, } ); }; export function blobToBase64(blob: Blob): Promise<string> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { const result = reader.result as string; // Remove the "data:*/*;base64," prefix if present const base64 = result.includes(",") ? result.split(",")[1] : result; resolve(base64); }; reader.onerror = (error) => reject(error); reader.readAsDataURL(blob); }); }
2. FormData上传方式
const handleSubmit = async (values: any) => { console.log(values); mutate( { username: values.username, bio: values.bio, profilePicture: values.profilePicture, }, { onSuccess: () => { router.push( `${ALL_LINKS.EXPLORE_PROFILE_SETTINGS.pageLink}?name=${values.username}` ); }, } ); }; export const basicInfo = async (payload: basicInfoPayload): Promise<BasicInfoResponse> => { try { // Create FormData using utility function const formData = objectToFormData(payload, { arrayFormat: "indexed", // exploreTags will be exploreTags[0], exploreTags[1], etc. excludeNull: true, excludeUndefined: true, }); const res = await http.post(API_ROUTES.AUTH.basicInfo.url, formData, { "Content-Type": "multipart/form-data", }); return res as BasicInfoResponse; } catch (error) { console.error("Unable to add information:", error); throw error; } };
可行解决方案
1. 修复FormData请求的Content-Type设置
KaiOS的fetch实现对手动设置multipart/form-data的边界值支持不佳,不要手动指定Content-Type,让浏览器自动生成包含正确边界的请求头:
export const basicInfo = async (payload: basicInfoPayload): Promise<BasicInfoResponse> => { try { const formData = objectToFormData(payload, { arrayFormat: "indexed", excludeNull: true, excludeUndefined: true, }); // 移除手动设置的Content-Type,让浏览器自动处理 const res = await http.post(API_ROUTES.AUTH.basicInfo.url, formData); return res as BasicInfoResponse; } catch (error) { console.error("Unable to add information:", error); throw error; } };
2. 优化Base64请求的 payload 大小与格式
KaiOS对大体积Base64数据的HTTP请求兼容性差,建议:
- 限制单张图片分辨率(如压缩至640x480),减少Base64字符串长度
- 确保请求头设置为
Content-Type: application/json,避免解析错误 - 分批次上传多张图片,避免单次请求体积过大
示例压缩图片的工具函数:
export async function compressBlob(blob: Blob, maxWidth = 640, maxHeight = 480): Promise<Blob> { return new Promise((resolve) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); let width = img.width; let height = img.height; if (width > height && width > maxWidth) { height *= maxWidth / width; width = maxWidth; } else if (height > maxWidth) { width *= maxHeight / height; height = maxHeight; } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx?.drawImage(img, 0, 0, width, height); canvas.toBlob(resolve, blob.type, 0.7); }; img.src = URL.createObjectURL(blob); }); }
使用时先压缩再转Base64:
const base64Images = await Promise.all( postData?.files?.map(async (file) => { const compressedBlob = await compressBlob(file); return blobToBase64(compressedBlob); }) );
3. 检查KaiOS的网络权限与CORS配置
- 确保应用在
manifest.webapp中声明了网络权限:"permissions": { "network": {} } - 后端需正确配置CORS,允许KaiOS设备的请求来源,避免因跨域导致的网络错误
4. 改用XMLHttpRequest替代fetch
KaiOS的fetch实现存在部分兼容性bug,切换到XMLHttpRequest可能解决问题:
export function uploadFormData(formData: FormData, url: string): Promise<any> { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', url); xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error(`Request failed with status ${xhr.status}`)); } }; xhr.onerror = () => reject(new Error('Network error occurred')); xhr.send(formData); }); }
内容的提问来源于stack exchange,提问作者Bhaskar Sharma
相关产品推荐
相关产品推荐

