最可靠方式是用 XMLHttpRequest 手动提交并监听 upload.onprogress,因 fetch 尚不支持上传进度;需阻止表单默认提交、用 FormData 收集数据、不手动设 Content-Type、校验 lengthComputable 防 NaN、上传完成设 progress.value=100。
用
监听上传进度最可靠
浏览器原生
表单提交
(
)不暴露上传过程,没法做进度条。必须改用
或
手动发请求,才能监听
。现代项目推荐用
,因为
目前仍不支持上传进度事件(
是草案,Chrome/Firefox 都没实现)。
常见错误是直接对
绑定
——这完全无效,事件根本不会触发。
先
阻止默认提交
用
收集字段(支持文件、文本、多选等)
创建
,监听
更新
元素的
注意:
只在上传阶段触发,不是整个请求生命周期
传文件时要避免手动设
如果用
发送
,千万别手动设置
头。浏览器会自动加上带随机 boundary 的
,手动覆盖会导致后端收不到文件(PHP 的
为空,Node.js 的
报错
)。
正确写法是让浏览器自动生成头:
立即学习
“
前端免费学习笔记(深入)
”;
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
如果需要额外参数(如 token),用
追加,别塞进 headers
纯 JSON 提交不用进度条,但若混传文件 + JSON 字段,必须用
,不能
元素更新要防 NaN 和重复触发
和
在小文件或本地测试时可能为 0,直接除会导致
,
会卡死或显示异常。同时,某些浏览器(如 Safari)会在上传结束前多次触发
,但
不一定只出现一次。
更新前加判断:
把
写死,不要依赖 JS 设置
提交按钮建议在开始上传时
,防止用户连点;成功/失败后再恢复
上传完成(
)后记得手动设
,避免因四舍五入差 0.1% 卡在 99%
服务端返回 200 但前端报错?检查响应体格式
进度条能动,但最终
拿不到数据,或者解析 JSON 失败,大概率是服务端返回了非 JSON 内容(比如 PHP 输出了 warning、Node.js 忘了
、Nginx 加了额外 header)。此时
可能是 HTML 或空字符串,
就会抛错。
用浏览器 DevTools 的 Network 面板看「Response」标签页,确认返回的是纯 JSON(如
)
后端务必关掉调试输出(PHP 的
,Python 的
关闭)
前端加兜底:
进度条本身不解决后端逻辑问题,但它把“卡住”变成了可观察的数值——这恰恰是最容易被忽略的:你看到进度走到 100%,不代表后端已处理完,只代表字节发完了。
XMLHttpRequestsubmitXMLHttpRequestfetchupload.onprogressXMLHttpRequestfetchUploadProgressform.submit()onprogressevent.preventDefault()new FormData(form)XMLHttpRequestupload.onprogressvalueonprogressFormDataContent-TypeXMLHttpRequestFormDataContent-Typemultipart/form-data$_FILESmulterUnexpected end of formxhr.open('POST', '/upload');
// ❌ 错误:xhr.setRequestHeader('Content-Type', 'multipart/form-data');
// ✅ 正确:什么都不设,让浏览器处理
xhr.send(formData);
formData.append('token', 'xxx')FormDataJSON.stringifyevent.loadedevent.totalNaNonprogressloaded === totalif (e.lengthComputable) { progress.value = (e.loaded / e.total) * 100; }maxdisabledxhr.onloadprogress.value = 100xhr.onloadres.end()xhr.responseJSON.parse{"ok":true}error_reporting(0)loggingtry { JSON.parse(xhr.response); } catch(e) { console.error('Invalid JSON:', xhr.response); }