React中XMLHttpRequestUpload的onprogress/loadend事件提前触发问题
问题解决思路
1. 服务器端请求缓冲是核心原因
大部分情况下,这种现象是因为服务器先缓存了整个请求体再处理,导致浏览器误以为上传已经完成(触发xhr.upload的进度和结束事件),但网络面板显示的是服务器后台处理文件的耗时,而非真实的上传耗时。
- 若用Nginx做反向代理,需配置
proxy_request_buffering off,禁止缓存请求体,让服务器实时接收文件块。 - 后端框架也可能有类似的请求缓冲配置,比如Express的
body-parser处理大文件时的设置,需调整为流式接收,而非一次性缓存。
2. 调整XHR事件绑定顺序
部分浏览器对时序敏感,建议把upload事件绑定放在xhr.open()之前,确保事件能被正确监听:
const uploadData = (method, url, data) => { const formData = new FormData(); formData.append('file', data); const xhr = new XMLHttpRequest(); // 先绑定upload相关事件 xhr.upload.onprogress = (e) => console.log(`Uploaded:${e.loaded} of ${e.total}`); xhr.upload.onloadend = (e) => console.log('finished'); xhr.open(method, url); return new Promise((resolve, reject) => { xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response); } else { reject({ status: xhr.status, statusText: xhr.statusText, }); } }; xhr.onerror = () => { reject({ status: xhr.status, statusText: xhr.statusText, }); }; xhr.send(formData); }); };
3. 校验传入的文件对象
确保data参数是标准的File或Blob对象,非标准对象会导致XHR无法正确识别文件大小,直接触发100%进度:
const uploadData = (method, url, data) => { // 新增校验 if (!(data instanceof File || data instanceof Blob)) { throw new Error('上传数据必须是File或Blob类型'); } const formData = new FormData(); formData.append('file', data); // 后续代码不变... };
4. 排除外部干扰
- 在浏览器无痕模式下测试,排除插件缓存的影响。
- 关闭代理工具,避免代理服务器提前缓存请求体。
内容的提问来源于stack exchange,提问作者Pooya
相关产品推荐
相关产品推荐

