- 概述
Access-Control-Expose-Headers 是一个 HTTP 响应头,属于跨域资源共享(CORS)规范的一部分。它用于告诉浏览器:在跨域请求中,允许客户端 JavaScript 访问哪些响应头字段。
简单来说,它是服务器向浏览器授予的一张"白名单",决定了前端代码能从 HTTP 响应中读取哪些头部信息。
- 背景与设计原因
2.1 同源策略的安全限制
浏览器的同源策略(Same-Origin Policy)严格限制了网页脚本(如 JavaScript)跨域读取资源。即使通过 CORS 机制放宽了请求限制(允许跨域发送请求),浏览器出于安全考虑,仍然默认不会将所有的响应头暴露给前端代码。
2.2 默认暴露的"简单响应头"
在 CORS 规范中,只有一组被称为 简单响应头(Simple Response Headers)的字段,默认可以被前端通过 getResponseHeader() 或 fetch 等方式读取。这些包括:
· Cache-Control
· Content-Language
· Content-Type
· Expires
· Last-Modified
· Pragma
2.3 为什么要限制
如果服务器返回了任何自定义的响应头(如 X-Total-Count、Authorization、X-User-Id),浏览器会将其屏蔽,不暴露给 JavaScript。这种设计是为了防止恶意网站利用跨域请求,随意读取敏感信息(例如服务器返回的私有令牌),从而保护用户数据安全。
- 作用与核心功能
Access-Control-Expose-Headers 的核心作用是 显式授权。当服务器在响应中包含该头时,便明确告知浏览器:"这些额外的头部是安全的,允许前端代码读取它们。"
3.1 使自定义头可读
服务器可以列出任何希望前端访问的响应头名称。例如:
```http
Access-Control-Expose-Headers: X-Total-Count, X-Request-ID, Content-Range
```
前端随后便可通过 JavaScript 读取这些头:
```javascript
fetch('https://api.example.com/data')
.then(response => {
const totalCount = response.headers.get('X-Total-Count');
const requestId = response.headers.get('X-Request-ID');
console.log(totalCount, requestId);
});
```
3.2 支持多个值
该头可以指定多个头部名称,用逗号分隔。也可以使用通配符 *(在允许凭据的请求中可能受限),表示允许暴露所有响应头。
3.3 配合 CORS 预检请求
对于非简单请求(如使用 PUT 方法或携带自定义头),浏览器会先发送一个 OPTIONS 预检请求。服务器在预检响应中也可以包含 Access-Control-Expose-Headers,告知浏览器在实际请求中哪些头部可以被读取。
- 典型使用场景
· 分页信息传递
RESTful API 常在 X-Total-Count 或 Content-Range 头中返回总记录数。前端需要读取这些头来实现分页组件。
· 文件上传进度
服务端可能通过 X-Upload-Progress 或类似自定义头返回上传状态。
· 自定义请求追踪
后端通过 X-Request-ID 返回唯一请求标识,便于前端收集日志或调试。
· 令牌刷新机制
在身份验证场景中,服务器可能在响应头中返回新的 Authorization 或 X-Refresh-Token,前端需要读取并存储。
- 注意事项
· 仅对跨域请求生效:同源请求不受此限制,所有响应头默认均可被读取。
· 预检响应中的位置:该头既可以在实际响应中返回,也可以在预检(OPTIONS)响应中返回。通常在实际响应中包含即可。
· 通配符 * 的限制:如果请求包含凭据(credentials: 'include'),则 Access-Control-Expose-Headers 不能使用 *,必须明确列出具体头部名称。
· 大小写不敏感:HTTP 头部名称不区分大小写,但建议使用标准格式(如 X-Custom-Header)。
· 并非所有浏览器行为一致:虽然现代浏览器均已支持,但在开发中建议始终明确列出所需暴露的头部,避免依赖默认行为。