Access-Control-Expose-Headers 是服务端设置的响应头,用于显式授权前端 JavaScript 读取指定的自定义响应头;浏览器默认仅允许访问 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 这6个简单响应头,若后端返回 X-Request-ID 等自定义头却未在该头中声明,则 response.headers.get() 将返回 null。

Access-Control-Expose-Headers 是服务端设置的响应头,不是 JS 客户端代码能“用”或“设置”的。JS 本身无法直接控制或添加这个头——它必须由后端(如 Node.js、Nginx、Spring Boot 等)在 HTTP 响应中显式返回,客户端 JS 才能在 fetch 或 XMLHttpRequest 中读取被暴露的自定义响应头。
为什么需要 Access-Control-Expose-Headers
浏览器默认只允许 JS 读取一部分“简单响应头”,比如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果你的服务端返回了自定义头(例如 X-Request-ID、X-RateLimit-Remaining),但没通过 Access-Control-Expose-Headers 显式声明,JS 调用 response.headers.get('X-Request-ID') 就会返回 null,即使网络面板里能看到该头。
服务端怎么设置(关键步骤)
你必须在后端响应中同时满足两个条件:
- 设置
Access-Control-Allow-Origin(支持跨域) - 在同一个响应中,用
Access-Control-Expose-Headers列出你想让 JS 读取的自定义头,多个用英文逗号+空格分隔
示例(Express.js):
app.get('/api/data', (req, res) => {
res.set({
'Access-Control-Allow-Origin': 'https://your-frontend.com',
'Access-Control-Expose-Headers': 'X-Request-ID, X-RateLimit-Remaining',
'X-Request-ID': 'abc123',
'X-RateLimit-Remaining': '42'
});
res.json({ ok: true });
});
JS 客户端怎么安全读取
确保使用 fetch(或 XMLHttpRequest),且响应头已被正确暴露后,再调用 .headers.get():
fetch('https://api.example.com/data')
.then(res => {
// ✅ 可以读取(前提是服务端已暴露)
console.log(res.headers.get('X-Request-ID')); // 'abc123'
console.log(res.headers.get('X-RateLimit-Remaining')); // '42'
// ❌ 未暴露的头将返回 null
console.log(res.headers.get('X-Secret')); // null
});
注意:res.headers.get() 区分大小写,建议按服务端实际发送的大小写来写;不能用点号访问(如 res.headers.X-Request-ID),只能用 get() 方法。
常见踩坑提醒
- 前端无法绕过限制:即使你在浏览器 Network 面板看到自定义头,JS 读不到就是没暴露,别试图用 JS “修复”
-
预检请求(OPTIONS)也要暴露:如果请求触发预检(如带认证、非简单方法),确保 OPTIONS 响应也包含
Access-Control-Expose-Headers -
不能暴露
Set-Cookie或Authorization:这些头被浏览器硬性禁止暴露,设了也无效 -
通配符
*不适用于Access-Control-Expose-Headers:必须明确列出每个头名,不支持Access-Control-Expose-Headers: *


















