只有done回调能拿到解析后的JSON对象,因Layui仅在响应体为合法JSON、Content-Type为application/json且状态码匹配配置时才触发done并传入已解析对象,其他入口不可靠。
必须走 done 回调,其他入口(success、complete、手动读 xhr.responsetext)都不可靠——layui 不暴露原生 xhr,也不在非 done 钩子中解析响应体。
为什么只有 done 能拿到解析后的 JSON 对象
Layui upload 内部只在满足三个条件时才触发 done 并传入已解析对象:响应体是合法 JSON 字符串、Content-Type 为 application/json、且状态字段(默认 code)值等于配置的 statusCode(默认 0)。任一不满足,就跳过 done 直接进 error 或静默失败。
常见误判:HTTP 状态码是 200,但后端返回了 HTML 片段或带 BOM 的 JSON,Layui 会因 JSON.parse() 报错而弃用整个响应体。
-
done的res参数一定是 JS 对象,不是字符串 -
error回调里拿不到res,只有index和upload实例 - 不要在
choose或before里尝试提前读取服务器返回——此时请求还没发
response 配置必须显式声明字段映射
后端返回 {"status":1,"message":"ok","payload":{"url":"/upload/a.jpg"}}?Layui 默认只认 code,不配 response 就永远进不了 done。
这个配置不是可选装饰项,而是桥接协议的关键开关:
-
statusName: 'status'—— 告诉 Layui 从res.status取状态码 -
statusCode: 1—— 指定值为1才算成功(而非默认的0) -
msgName: 'message'—— 错误提示从res.message提取 -
dataName: 'payload'—— 实际数据在res.payload下,done中直接用res.payload.url
示例完整配置:
layui.upload.render({
elem: '#upload',
url: '/api/upload',
response: {
statusName: 'status',
statusCode: 1,
msgName: 'message',
dataName: 'payload'
},
done: function(res) {
console.log(res.payload.url); // ✅ 正确取到路径
}
});
后端返回必须是干净的 JSON 字符串
哪怕结构完全正确,只要响应体开头有 BOM、中间多了一个空格、结尾多了个 var_dump(),Layui 就会解析失败并进 error。
PHP 示例(避坑写法):
header('Content-Type: application/json; charset=utf-8');
if (ob_get_level()) ob_end_clean(); // 清掉所有前置输出
$result = [
'status' => 1,
'message' => '上传成功',
'payload' => ['url' => '/uploads/20260630/abc.png']
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
- 绝对不用
print_r()、die('success')、echo '<html>...' - 框架如 ThinkPHP/Laravel 需确认是否自动加了 layout 或调试信息
- IE8 等旧浏览器要求
Content-Type改为text/html,且后端必须返回字符串而非数组(json_encode结果)
done 里取不到字段?先查字段名是否完全一致
Layui 不做字段转换,res 就是后端返回 JSON 的 JS 对象映射。后端返回 {"fileUrl":"/x.jpg"},前端就必须写 res.fileUrl,写 res.data 或 res.url 都是 undefined。
- 检查大小写:后端是
file_url,前端不能写res.fileUrl(除非服务端做了驼峰转换) - 检查嵌套层级:返回
{"data":{"src":"/a.jpg"}},就要用res.data.src,不是res.src - 用
console.log(res)看清实际结构,别凭印象写字段名
最常被忽略的是:后端字段名和服务端约定不一致,又没配 response.dataName,导致前端以为数据在顶层,其实藏在 res.data 或 res.payload 里。


















