Access-Control-Expose-Headers用于指定前端JavaScript可读取的响应头白名单,默认仅允许Cache-Control等6个安全头部;需显式声明ETag、X-Total-Count等自定义头才能通过getResponseHeader()获取。

在跨域(CORS)场景下,浏览器默认只允许前端 JavaScript 读取一小部分“安全”的响应头,比如 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified 和 Pragma。其余自定义或非标准响应头(包括 ETag、X-Total-Count、X-RateLimit-Remaining 等),即使服务端返回了,前端 JS 也无法通过 response.headers.get('ETag') 获取——除非服务端显式声明暴露。
关键响应头是:
Access-Control-Expose-Headers
它用于指定哪些响应头可以被前端 JS 安全读取。这是一个白名单机制,必须由服务端主动设置。
立即学习“前端免费学习笔记(深入)”;
-
✅ 必须包含
ETag才能用 JS 读取:Access-Control-Expose-Headers: ETag, X-Request-ID, X-Total-Count
-
❌ 如果没暴露
ETag,即使响应中实际包含:ETag: "abc123"
前端调用
response.headers.get('ETag')会返回null,且控制台无报错,容易误判为服务端没返回。
常见需暴露的缓存/元数据类响应头包括:
-
ETag—— 用于条件请求(如If-None-Match)和缓存验证 -
Last-Modified—— 配合If-Modified-Since使用(虽属“安全头”,但部分旧浏览器仍建议暴露) -
Cache-Control—— 默认可读,无需暴露 -
Expires—— 默认可读 - 自定义缓存标识头,例如:
-
X-Cache-Status(CDN 缓存命中状态) -
X-Edge-Cache-Hit(边缘节点缓存标识) -
X-Backend-Time(后端处理耗时)
-
注意两点:
-
Access-Control-Expose-Headers的值是逗号分隔的头名称列表,不带空格更稳妥(如ETag,X-Total-Count) - 它只影响
fetch()或XMLHttpRequest的getResponseHeader()/headers.get()行为,不影响浏览器自身缓存逻辑(如ETag仍会被浏览器自动用于 304 判定,无论是否暴露)
不复杂但容易忽略


















