上传失败日志必须在xhr.onerror、xhr.onload(检查status)和onprogress中捕获,且需用lengthComputable判断防除零错误;console.log不持久,真留痕应存内存或localStorage后批量上报。

上传失败时日志必须在 xhr.onerror、xhr.onload(检查 xhr.status)和 onprogress 中捕获,且不能直接写文件或高频上报——否则会卡住上传流程。
为什么 console.log 不算真正保存日志
浏览器控制台输出不持久,刷新即丢;用户无法导出,排查时找不到上下文。真要留痕,得把错误信息存进内存队列或 localStorage,等上传完成或页面卸载前批量发给后端。
- 错误字段至少含:
file.name、xhr.status、xhr.statusText、new Date().toISOString()、网络状态navigator.onLine - 不要在
onerror里立刻调fetch('/log'):并发日志请求可能压垮弱网设备 - 若用
localStorage存日志,单条建议 ≤2KB,总量不超过 5MB,避免触发 QuotaExceededError
xhr.upload.onprogress 里记日志的致命陷阱
e.total 在服务端没返回 Content-Length 时为 0,直接算百分比会触发 NaN 或除零错误,导致整个监听器崩溃,连失败回调都进不去。
- 必须加
if (e.lengthComputable)判断,否则e.total === 0时跳过计算 - 进度日志建议节流:用
setTimeout+ 标志位,确保 500ms 内最多记一次,避免刷屏式写入 - 别在进度回调里做 DOM 更新+日志+上报三件事,拆成独立逻辑链更可控
如何把失败日志可靠发到后端
不能依赖上传主请求的失败回调立刻发日志——此时网络大概率已异常,再发一个请求极可能也失败。稳妥做法是:先存本地,再择机补传。
立即学习“前端免费学习笔记(深入)”;
- 用
localStorage.setItem('upload_logs', JSON.stringify(logsArray))持久化(注意转义特殊字符) - 监听
beforeunload事件,在关闭页签前尝试发一次;若失败,下次打开页面时检查是否有未发送日志 - 后端接收日志的接口必须是轻量 GET 或带重试的 POST,路径如
/api/log/upload-fail,别走和上传同个鉴权中间件(失败时 token 可能已过期) - 日志体用最小结构:
{file_name: "a.pdf", status: 0, error: "network error", ts: "2026-09-22T01:30:00Z"}
最易被忽略的是:服务端返回 4xx 错误(比如 413 Payload Too Large)时,xhr.onerror 不触发,只有 xhr.onload 被调用——必须在这里判断 xhr.status < 400 || xhr.status >= 500 才算成功,其余都归为失败并记日志。



















