上传失败时应通过监听网络错误和HTTP状态码提取具体原因再alert:fetch需catch网络异常并检查response.ok,用headers判断JSON后安全解析;XMLHttpRequest需区分ontimeout/onabort/onerror;iOS Safari需确保alert在用户手势同步调用。

上传失败时如何用 alert() 显示错误原因
直接调用 alert() 不够——它只能显示固定文字,而真实失败往往有具体原因(如网络中断、文件过大、后端拒绝)。必须从请求响应中提取错误信息再展示。
常见错误现象:用户点了上传按钮没反应,或只弹出“上传失败”,但不知道是自己选错了文件,还是服务器挂了。
- 前端发起上传时,务必监听
onerror(XMLHttpRequest)或catch(fetch),而不是只看onload - 如果用
fetch,response.ok === false不代表网络失败,而是 HTTP 状态码非 2xx,此时仍需读取response.text()或response.json()获取后端返回的提示 - 不要在
catch里直接alert('网络错误')——真实场景中,fetch的catch只捕获网络层异常(如断网、DNS 失败),4xx/5xx 状态码不会进这里
后端返回 JSON 错误时怎么安全解析并弹窗
很多后端在上传失败时返回类似 {"code":400,"msg":"文件大小不能超过 2MB"},但前端若不校验格式就直接 JSON.parse(),可能因返回纯文本 HTML(如 Nginx 502 页面)而报错,导致弹窗也不出现。
- 用
response.headers.get('content-type')?.includes('json')初步判断响应是否为 JSON - 用
try/catch包裹await response.json(),解析失败则 fallback 到await response.text() - 最终弹窗内容优先取
data.msg或data.message,没有则用text全文,避免alert(undefined)
fetch('/upload', { method: 'POST', body: formData })
.then(r => r.ok ? r.json() : Promise.reject(r))
.then(data => console.log('成功'))
.catch(err => {
if (err.json) {
err.json().then(data => alert(data.msg || data.message || '上传失败')).catch(() => alert('未知错误'));
} else {
alert(err.status + ' ' + err.statusText || '上传失败');
}
});
用 XMLHttpRequest 时怎么区分超时、取消和真实服务端错误
XMLHttpRequest 的 onerror 会同时触发网络失败、跨域拒绝、HTTPS 混合内容等场景,但无法直接区分;而 ontimeout 和 onabort 是独立事件,必须单独监听。
立即学习“前端免费学习笔记(深入)”;
- 设置
xhr.timeout = 10000后,必须绑定xhr.ontimeout,否则超时会被吞进onerror,和真正网络错误混在一起 -
xhr.upload.onprogress中若用户手动调用xhr.abort(),会触发onabort,这时不应弹“上传失败”,而应提示“已取消” - 服务端返回 413(Payload Too Large)时,
xhr.status是 413,xhr.statusText是 "Request Entity Too Large",可直接用于提示
移动端 Safari 上传失败弹窗被拦截怎么办
iOS Safari 对非用户手势触发的 alert() 会静默屏蔽——比如上传逻辑放在 setTimeout 或 Promise 微任务中,即使源头是点击按钮,也可能失效。
- 确保
alert()调用栈顶部是原生事件(如input[type=file].onchange或button.onclick),中间不要穿插异步跳转 - 更稳妥的做法是用 DOM 模拟弹窗:
document.body.innerHTML += '<div class="alert">...</div>',避免依赖浏览器原生行为 - 如果必须用
alert(),可在事件回调开头加if (!event.isTrusted) return;防止被自动触发逻辑误用
上传失败的提示不是“有没有”,而是“准不准、及时不及时”。后端返回的 msg 字段经常拼错成 message 或 error,前端不兼容就只能弹“失败”两个字——这种细节,上线前用抓包工具改响应体测一遍最实在。



















