CloudFront返回的S3源CORS头部异常,部分跨域请求失败求助
咱们一步步拆解你的问题,先搞定C.dev.example.com请求失败的事儿,再处理CloudFront返回CORS头部不稳定的情况:
一、为什么C.dev.example.com请求会失败?
同一份S3 CORS配置下,A.example.com能成但C.dev.example.com不行,大概率是这几个原因:
请求是否携带了凭证(Cookie/HTTP认证信息)?
如果你的C.dev.example.com页面带登录态,jQuery的跨域请求可能默认携带Cookie,而你的S3 CORS配置里没允许凭证。浏览器会拦截这种带凭证但响应里没有Access-Control-Allow-Credentials: true的请求。
先打开浏览器开发者工具,看看C.dev.example.com的请求有没有Cookie头,再看预检OPTIONS请求的响应头。如果是这个问题,更新S3的CORS配置:<CORSConfiguration> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> <AllowCredentials>true</AllowCredentials> </CORSRule> </CORSConfiguration>要是不需要带凭证,也可以在jQuery请求里加
xhrFields: { withCredentials: false },强制不发送凭证。CloudFront缓存是否“记住了”旧的CORS规则?
CloudFront默认不会把Origin头作为缓存键的一部分,如果A.example.com先发起请求,CloudFront缓存了对应响应;要是之前S3的CORS配置不一样,旧缓存可能导致C.dev.example.com的请求拿到错误的响应头。先手动刷新CloudFront对应路径(B.example.com/file.js)的缓存,再测试。确认C.dev.example.com的Origin值是否正常
虽然你用了AllowedOrigin:*,但偶尔浏览器对子域名的Origin解析可能有小问题(比如带了非标准端口?),在C.dev.example.com的控制台执行console.log(window.location.origin),确认Origin格式是https://C.dev.example.com这种标准格式。
二、解决CloudFront返回CORS头部持续变化的问题
这个问题90%是CloudFront缓存策略没正确处理Origin头导致的,按下面步骤来:
把Origin头加入CloudFront缓存键
登录CloudFront控制台,找到你的分发:- 进入「缓存策略」标签,新建或修改现有缓存策略;
- 在「缓存键和源请求」里,把
Origin添加到「包含在缓存键中的请求头」(选自定义,手动加Origin);
这样CloudFront会根据不同的Origin值缓存不同的响应,不会让不同域名的请求共享同一个缓存条目,自然就不会出现CORS头波动的情况。
确保CloudFront把Origin头转发给S3
在分发的「行为」设置里,编辑对应路径的行为,检查「源请求策略」,确保Origin头被转发到S3。S3需要根据Origin头生成正确的CORS响应,所以必须让CloudFront把这个头传过去。强制CloudFront返回固定的CORS头(可选)
既然你允许所有Origin(*),可以直接在CloudFront里设置自定义响应头,覆盖S3返回的内容,确保CORS头固定:- 在「行为」设置的「响应头策略」里,添加自定义响应头:
- 类型选「自定义」,头名称填
Access-Control-Allow-Origin,头值填*; - 开启「覆盖」选项,这样不管S3返回什么,CloudFront都会返回固定的
*。
- 类型选「自定义」,头名称填
- 在「行为」设置的「响应头策略」里,添加自定义响应头:
刷新CloudFront缓存
所有配置改完后,一定要手动刷新缓存!在CloudFront控制台选你的分发,点击「创建无效ation」,输入/*或者具体的/file.js路径,提交后等几分钟,旧缓存就会被清除,新策略就能生效了。
最后总结
先排查C.dev.example.com的请求是否带凭证,调整S3 CORS配置;再通过CloudFront的缓存策略、源请求策略处理Origin头,最后刷新缓存。这样两个问题应该都能解决。
内容的提问来源于stack exchange,提问作者M. Gara

