access-control-expose-headers由服务端设置,用于声明跨域响应中允许javascript读取的非简单响应头,需与access-control-allow-origin配合使用,且不可写*;前端通过res.headers.get()获取,区分大小写。

JavaScript 本身不能限制客户端可访问的响应头——这是服务器端通过 Access-Control-Expose-Headers 响应头控制的。浏览器在收到跨域响应后,只会把“简单响应头”(如 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma)默认暴露给 JavaScript;其他自定义或特殊响应头(比如 X-Request-ID、X-RateLimit-Remaining、ETag)必须由服务端显式声明,前端才能在 response.headers.get() 中读取。
服务端必须设置 Access-Control-Expose-Headers
这个响应头的作用是:告诉浏览器,“除了默认允许的那些,我还额外允许 JS 读取以下这些响应头”。它只影响跨域请求中 JavaScript 能否获取响应头,不影响服务端实际返回哪些头。
- 只写需要被前端读取的头,避免暴露敏感信息(如
Server、X-Powered-By、内部追踪 ID) - 多个头用英文逗号+空格分隔,例如:
X-Request-ID, X-RateLimit-Reset, ETag - 不能写
*(该写法已被现代浏览器废弃,不生效) - 必须配合
Access-Control-Allow-Origin一起使用,否则整个 CORS 响应无效
常见配置示例
不同后端框架写法略有差异,但逻辑一致:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Express.js:
res.set('Access-Control-Expose-Headers', 'X-Request-ID, X-RateLimit-Remaining') -
Nginx:
add_header 'Access-Control-Expose-Headers' 'X-Request-ID, ETag'; -
Spring Boot:在控制器方法加注解
@CrossOrigin(exposeHeaders = {"X-Request-ID", "ETag"}) -
Python Flask:
response.headers['Access-Control-Expose-Headers'] = 'X-Request-ID, X-RateLimit-Reset'
前端如何读取被暴露的响应头
只要服务端正确设置了 Access-Control-Expose-Headers,前端就可以用标准 fetch API 获取:
fetch('/api/data')
.then(res => {
console.log(res.headers.get('X-Request-ID')); // ✅ 可读(如果服务端已暴露)
console.log(res.headers.get('X-Internal-Token')); // ❌ 未暴露则返回 null
});
注意:res.headers.get() 区分大小写,且只能在响应成功(status in 200–299)时调用;若响应是 4xx/5xx,部分浏览器可能限制访问自定义暴露头。
容易忽略的关键点
-
Access-Control-Expose-Headers不影响服务端是否发送某个响应头,只影响浏览器是否允许 JS 读取它 - 即使没暴露,开发者工具 Network 面板仍能看到所有响应头——这只是调试视图,不代表 JS 能访问
- 如果前端依赖某个头做业务逻辑(如重试依据
Retry-After),而服务端未暴露,JS 就拿不到,会导致逻辑中断 - 和
Access-Control-Allow-Headers不同:后者控制“前端能发哪些请求头”,前者控制“前端能读哪些响应头”,两者作用方向相反,别混淆
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










