layui upload 的 done 回调需显式声明第四个参数 xhr 才能读取响应头,通过 xhr.getresponseheader() 获取,且后端必须在 access-control-expose-headers 中暴露对应 header。

layui upload 无法在 done 回调里直接拿到响应头,必须通过 xhr 参数手动读取
done 回调的第四个参数 xhr 是唯一入口
layui 的 upload.render() 的 done 回调签名是 done(res, index, upload, xhr),其中 xhr 是原生 XMLHttpRequest 实例——只有它能访问响应头。别指望 res 或其他参数自动解析 header。
-
res是 JSON 解析后的响应体,不含 header - 如果你没传第四个参数名(比如写成
done(res, i, inst)),xhr就彻底丢了 - 必须显式声明第四个形参,才能用
xhr.getResponseHeader('X-Request-ID')这类方法
获取自定义 Header 的正确写法
后端若返回了 X-Trace-ID 或 X-Rate-Limit-Remaining 这类字段,前端要这样取:
done: function(res, index, upload, xhr) {
// ✅ 正确:用 xhr.getResponseHeader()
var traceId = xhr.getResponseHeader('X-Trace-ID');
var rateLimit = xhr.getResponseHeader('X-Rate-Limit-Remaining');
// ❌ 错误:xhr.headers 不存在,xhr.responseHeaders 也不对
// console.log(xhr.headers); // undefined
// console.log(xhr.responseHeaders); // undefined
// ⚠️ 注意大小写:HTTP header 名不区分大小写,但 getResponseHeader 接受任意大小写写法
// 'x-trace-id'、'X-Trace-ID'、'x-Trace-Id' 都可以
}
- 如果返回
null,说明后端根本没发这个 header,或被 CORS 拦截了(见下一条) - 跨域时,浏览器默认只暴露
Cache-Control、Content-Language、Content-Type等少数几个 header;自定义 header 必须由后端在Access-Control-Expose-Headers中显式声明 - 例如后端需返回:
Access-Control-Expose-Headers: X-Trace-ID, X-Rate-Limit-Remaining,否则getResponseHeader永远返回null
常见失败原因:CORS 暴露头缺失 + 预检失败
即使后端写了 Access-Control-Expose-Headers,如果上传请求触发了预检(OPTIONS),而预检响应里没包含它,依然拿不到。
- 什么会触发预检?加了自定义 header(如
Authorization)、非标准Content-Type(但 upload 不会设application/json,所以一般不会) - 检查浏览器 Network 面板里的 OPTIONS 请求响应头,确认
Access-Control-Expose-Headers存在且值正确 - 如果后端用的是 Express,需确保 CORS 中间件配置了
exposedHeaders选项,不能只配headers - Spring Boot 用户注意:
@CrossOrigin(exposedHeaders = "X-Trace-ID")必须加在 Controller 方法或类上,全局配置可能不生效
真正容易被忽略的是:header 名必须同时出现在后端响应和 Access-Control-Expose-Headers 里,缺一不可;而且 done 回调里漏写第四个参数 xhr,就等于主动放弃读取权限。









