html表单上传进度需用xmlhttprequest.upload.onprogress监听,常见错误是绑定到xhr而非xhr.upload,且须在open后、send前设置;若后端无content-length则lengthcomputable为false。

HTML 表单本身不支持上传进度显示,必须用 XMLHttpRequest.upload.onprogress 手动监听;fetch 无法监听上传进度,别试了。
为什么 onprogress 一直不触发
最常见原因是监听对象写错了:必须绑定到 xhr.upload,而不是 xhr 本身。比如写成 xhr.onprogress = ... 就是监听下载事件,跟上传无关。
- 必须在
xhr.open()之后、xhr.send()之前设置xhr.upload.onprogress - 如果后端没返回
Content-Length(比如被 Nginx 截断、或用了某些代理),e.lengthComputable会是false,e.total为0,此时没法算百分比 - Safari 对小文件的
upload.onprogress触发极不规律,可能只触发一次,这不是 bug,是它的实现策略 - 用
curl -I http://your-api/upload检查响应头,确认有Content-Length字段
FormData 构建时容易出错的点
进度条能动,不代表后端真收到了文件。很多上传失败其实是 FormData 构造不当导致的。
- 文件字段名必须和服务端约定一致,比如后端 expect
file,你却append('myfile', file),就收不到 - 不要手动设置
Content-Type请求头——XMLHttpRequest会自动加multipart/form-data; boundary=xxx,设了反而破坏解析 -
append()和set()行为不同:重复 key 时,append()会保留多个值,set()只留最后一个,取决于后端框架怎么处理(如 multer 默认只取第一个) - 同时传 JSON 和文件时,别把 JSON 字符串
append('data', JSON.stringify(obj)),应改用纯字段拆开传,或让后端支持嵌套 multipart
用 <progress></progress> 还是自定义 <div>
<p><code><progress></progress> 语义清晰,但样式控制麻烦,各浏览器伪元素不统一;<div> 方案更可控,尤其需要动画、文字居中、多状态提示时。
<ul>
<li>用 <code><progress></progress> 时,必须用 JavaScript 动态更新 value 属性,不能只改 style.width
<div class="progress-bar"><div class="progress"></div></div> + CSS transition
onprogress 可能高频触发,但 UI 更新没必要每毫秒都刷,可用 requestAnimationFrame 或简单计时器限制更新频率真正卡住的地方往往不是代码写不对,而是后端悄悄截断了 Content-Length,或者前端把 onprogress 绑在了 xhr 而不是 xhr.upload 上——这两个点,90% 的“进度条不动”问题都出在这儿。











