HTML5文件上传需用选文件,进度显示必须通过XMLHttpRequest监听upload.onprogress事件实现,fetch不直接支持;关键要检查event.lengthComputable,且服务端须正确返回Content-Length响应头。

HTML5 文件上传用 就够了,但进度显示必须靠 JavaScript
纯 HTML5 标签本身不提供上传进度反馈。进度条依赖 XMLHttpRequest 或 fetch 配合 upload.onprogress 事件, 只负责选文件。
- 别指望给
加个属性就能出进度——没有这种属性 - 必须监听
XMLHttpRequest.upload.onprogress,不是request.onprogress -
fetch不直接支持上传进度,需配合ReadableStream分块读取 +AbortController手动模拟,复杂度高,推荐用XMLHttpRequest
用 XMLHttpRequest 实现带进度的上传
核心是创建实例、监听 upload.onprogress、手动发送 FormData:
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
// 关键:监听 upload 对象,不是 xhr 本身
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const percent = (event.loaded / event.total) * 100;
console.log(上传中:${percent.toFixed(1)}%);
// 更新进度条 DOM,例如:document.getElementById('bar').style.width = ${percent}%;
}
};
xhr.onload = () => {
if (xhr.status === 200) {
console.log('上传完成');
}
};
const formData = new FormData();
formData.append('file', file);
xhr.send(formData);
});
- 务必检查
event.lengthComputable,否则event.total可能为 0(如服务端未返回Content-Length) - 后端需正确响应,至少返回
200 OK,且不能关闭连接过早 - 若后端用 multipart 解析(如 Express 的
multer),确保字段名(这里是'file')和服务端配置一致
常见失败原因:进度始终为 0% 或不触发 onprogress
这不是前端代码写错了,大概率是环境或服务端问题:
- 本地 file:// 协议下,
XMLHttpRequest可能被浏览器限制,务必跑在http://或https://下 - 服务端没返回
Content-Length响应头(尤其代理层如 Nginx 默认不透传),导致event.lengthComputable === false - 使用了
axios等封装库却没开启onUploadProgress选项,或误用了onDownloadProgress - 文件过大触发了浏览器内存限制,部分 Chrome 版本对超大文件的
onprogress触发不规律
移动端和 Safari 的兼容注意点
iOS Safari 15.4+ 才完整支持 upload.onprogress,旧版可能完全静默;Android WebView 行为也不统一:
立即学习“前端免费学习笔记(深入)”;
- 不要依赖
event.total计算百分比,可改用“已发送 chunk 数 / 预估总 chunk 数”做粗略估算(需分片上传) - 避免在
onprogress中频繁操作 DOM,iOS 上容易卡顿,建议用requestIdleCallback节流更新 - 如果必须支持老 Safari,考虑降级为“上传中…(无数字)”,或改用 WebKit-only 的
webkitRelativePath辅助判断是否开始上传
实际嵌入时,最易被忽略的是服务端是否真正支持并透传上传长度信息——前端写得再标准,Nginx 没配 proxy_buffering off 或后端框架吞掉了 Content-Length,进度条就永远停在 0%。










