layui 上传组件的 error 回调不触发 json 解析异常,因其在 done 前内部调用 json.parse() 并静默捕获错误、弹出提示,未交由用户 error 处理;须在 done 中通过 xhr.responsetext 手动 try/catch 解析。
直接在 error 回调里拿不到 json 解析异常——layui 把这类错误吞掉了,只留一个静默失败或弹出“数据格式错误”,必须从源头拦截。
为什么 error 回调不触发 JSON 解析异常
Layui 的上传组件(layui.upload)内部用 JSON.parse() 尝试解析响应体,但这个过程发生在 done 之前、且独立于 XHR 状态判断。一旦 JSON.parse() 抛错,它会直接调用 that.msg(text['data-format-error']) 并终止流程,根本不会走到你配置的 error 回调函数里。
- 现象:控制台没报 JS 错误,但上传后无反应 / 弹“PleasereturnJSON data format” /
done不执行 - 本质:不是网络失败,是解析阶段被 Layui 主动拦截并消化了
-
error只捕获 XHR 层级失败(如超时、404、500、跨域拒绝),不处理 JSON 解析失败
如何真正捕获并定位 JSON 解析异常
唯一可靠方式是绕过 Layui 默认解析逻辑,在 done 回调中手动接管响应体解析,并用 try/catch 捕获异常。
- 确保后端返回的是字符串(不是已解析对象),否则
done接收到的res可能已是对象,JSON.parse()会报错“unexpected token o” - 在
done中先检查typeof res === 'string',再尝试JSON.parse(res) - 把原始响应体(
xhr.responseText)也传进来,用于比对是否被浏览器自动解析过 - 示例写法:
layui.upload.render({
elem: '#test',
url: '/upload/',
done: function(res, index, upload, xhr) {
// xhr.responseText 是原始字符串,最可信
let raw = xhr.responseText?.trim();
if (!raw) {
console.error('上传响应为空', { res, xhr });
return;
}
try {
let data = JSON.parse(raw);
console.log('解析成功', data);
// 后续业务逻辑
} catch (e) {
console.error('JSON 解析失败', { raw, error: e.message });
// 这里可上报、提示用户、重试等
}
}
});
response 配置项对 JSON 解析异常毫无作用
response 里的 statusName、dataName 等字段,只影响 Layui 在解析成功后的字段提取逻辑,完全不参与 JSON 解析本身。即使你写了 response: { statusName: 'result_code' },只要响应体不是合法 JSON 字符串,照样触发 data-format-error。
- 别指望靠改
response来绕过解析失败 - 它只在
JSON.parse()成功后才生效;失败了就进不了这一步 - 如果你的后端返回 HTML 错误页(比如 PHP Fatal Error)、空格+JSON、或带 BOM 的 UTF-8,
response配置完全无效
IE8 下的特殊陷阱:响应体被当作文本而非 JSON
IE8 不支持 XMLHttpRequest.responseType = 'json',且对 Content-Type 极其敏感。哪怕后端返回了标准 JSON 和正确 header,IE8 也可能把整个响应体当字符串传给 done,但又不保证是纯 JSON 字符串(可能含不可见字符、BOM、换行等)。
- 务必在 IE8 环境下检查
xhr.responseText的首尾空白和编码 - 服务端需确保输出无 BOM、无多余空行、
Content-Type明确为application/json; charset=utf-8 - 前端建议统一用
JSON.parse(xhr.responseText.trim()),避免空格导致解析失败
真正要捕获 JSON 解析异常,就得放弃依赖 Layui 的默认路径,老老实实自己 parse、自己 catch——它不给你机会,你就得自己造个机会。











