进度条不触发的主因是:①误用 xhr.onprogress(应为 xhr.upload.onprogress);②事件绑定位置错误(须在 xhr.open() 与 xhr.send() 之间);③后端未返回 Content-Length 导致 e.lengthComputable 为 false。

xhr.upload.onprogress 必须正确绑定,且后端要返回 Content-Length,否则进度条根本不会动。
为什么 onprogress 从不触发
90% 的“进度条卡死”问题都出在这三处:
- 写成了
xhr.onprogress—— 这是监听下载的,上传事件必须挂到xhr.upload.onprogress - 监听代码放在
xhr.open()之前或xhr.send()之后 —— 必须夹在两者中间才生效 - 后端响应头没带
Content-Length,导致e.lengthComputable === false,e.total为 0;用curl -I https://your-api/upload检查确认
Safari 对小文件(比如小于 1MB)的 upload.onprogress 触发极不规律,可能只发一次,这不是 bug,是它的流式上传策略。
用 <progress> 还是自定义 <div>
<progress> 语义清晰、代码少,但样式难统一:Chrome 用 ::-webkit-progress-bar,Firefox 用 ::-moz-progress-bar,没法一套 CSS 走天下。
立即学习“前端免费学习笔记(深入)”;
用 <div> 更可控,尤其要加文字居中、失败态提示、过渡动画时:
- 必须加
transition: width 0.2s ease,否则宽度突变很生硬 - 更新
progressEl.value才有效,只改style.width对<progress>没用 - 建议节流:高频
onprogress下,用requestAnimationFrame或时间戳限制每 100ms 最多更新一次 UI
FormData 构造不当,进度动了但后端收不到文件
进度条走完 ≠ 文件上传成功。常见坑点:
- 字段名不匹配:后端 expect
file,你却formData.append('myfile', file),服务端直接丢弃 - 手动设
Content-Type请求头 ——XMLHttpRequest会自动加multipart/form-data; boundary=xxx,设错就解析失败 -
append()和set()行为不同:重复 key 时,append()留多个值,set()只留最后一个;Express + multer 默认只取第一个 - 别
append('data', JSON.stringify(obj))—— 应拆成独立字段,或让后端支持嵌套 multipart 解析
后端配合的关键点不能漏
前端再准,后端一拦,进度就崩:
- Node.js + Express:禁用全局
body-parser(它会缓存整个请求体),改用multer或busboy流式接收 - PHP:确认
upload_max_filesize和post_max_size足够大,且未启用mod_security - Nginx 代理时默认删
Content-Length,需加配置:proxy_http_version 1.1和proxy_buffering off - 跨域场景下,后端必须返回
Access-Control-Allow-Headers: X-Requested-With等必要头
真正卡住的地方往往不是代码写不对,而是后端悄悄截断了 Content-Length,或者前端把 onprogress 绑在了 xhr 而不是 xhr.upload 上 —— 这两个点,必须先验。



















