iOS设备通过HTML/JS实现Base64文件上传时大文件报错问题咨询
问题根因
该报错和大小限制和iOS本身的Base64处理无关,是Safari浏览器对HTML 元素的value属性长度存在隐藏阈值,刚好对应200KB文件转Base64后的字符串长度,超过这个阈值的字符串写入input value时会被自动截断,就会出现"unterminated string literal"的语法错误。此前测试得到的内存阈值是JS运行时的堆内存限制,和DOM元素的属性存储限制不属于同一套规则,所以会出现内存充足但存储失败的情况。
可行规避方案(最小改动保留原有代码逻辑)
- 方案1:替换存储介质,放弃用hidden input存大体积JSON
原有逻辑里把整个图片Base64数组序列化后存到ContentPlaceHolder1_hd_images的操作直接改为存入sessionStorage,表单提交前再读取对应值传给后端即可,原有Base64处理、去重、缩略图生成逻辑完全不用修改。 - 方案2:分片存储到多个hidden input
如果后端逻辑要求必须用表单input提交图片数据,就把序列化后的长JSON按每100KB长度切分为多个分片,每个分片存到一个动态生成的hidden input里,后端接收后自行拼接即可,原有前端业务逻辑无需调整。 - 方案3:新增前端自动压缩逻辑
在读取文件转Base64的步骤前新增自动压缩逻辑,将所有图片自动压缩到200KB以内再转Base64,已验证压缩后的小文件可以正常上传,该方案不需要修改原有存储和提交逻辑。 - 额外注意:确保Base64读取完成后再执行saveimage
当前的saveimage是async函数,但如果是在FileReader的load事件触发前就调用该函数,b64txt里的内容是不完整的,也会触发相同报错,建议把saveimage的调用绑定到FileReader的onloadend回调中,确保Base64完全写入DOM后再执行后续逻辑。
优化后代码示例(以方案1为例,改动极小)
async function saveimage() { var imageexists = false; // 新增取值缓存,避免重复读取DOM多次split const b64Value = document.getElementById("b64txt").value; var base64result = b64Value.split(',')[1]; var filetype = b64Value.split(',')[0]; var filename = document.forms[1]['pic'].files[0].name; // 校验文件是否已存在 for (i = 0; i < images.length; i++) { if (images[i].base64 == base64result && images[i].filetype == filetype && images[i].filename == filename) { imageexists = true; } } if (imageexists == false) { var img = new image(base64result, filename, filetype); images.push(img); var json = JSON.stringify(images); // 替换原hidden input存储为sessionStorage存储 sessionStorage.setItem("hd_images", json); // 若需要兼容原有提交逻辑,可保留小长度值写入原input,大值走sessionStorage // document.getElementById("ContentPlaceHolder1_hd_images").value = json; } showthumbnails(); } // 表单提交时补充读取逻辑即可 // 示例:document.getElementById("ContentPlaceHolder1_hd_images").value = sessionStorage.getItem("hd_images")
内容的提问来源于stack exchange,提问作者Usman
相关产品推荐
相关产品推荐

