IIS CORS模块的Access-Control-Allow-Origin为何出现缓存现象?
Hey, 看起来你碰到了IIS CORS模块的一个经典缓存坑!我帮你拆解一下问题的来龙去脉和解决办法:
问题重现
首先,你用这段JS尝试跨域加载图片(先提一句,原代码里有个语法错误:var testImage = var Image;应该改成var testImage = new Image();,不然跑不起来):
var testImage = new Image(); testImage.crossOrigin = 'anonymous'; testImage.src = 'https://cdn.example.com/testImage.png';
测试时发现了很诡异的现象:
- 第一次从
https://www.first_domain.com请求图片,服务器返回的Access-Control-Allow-Origin是这个域名,请求正常通过; - 紧接着用另外两个已授权的域名(
second_domain.com、third_domain.com)请求,服务器居然还是返回first_domain.com的Origin值,直接被浏览器拦截; - 等个4分钟左右,再用
second_domain.com请求,这次返回对应域名,请求正常,但再切回第一个域名又被拒绝; - 再等4分钟,第三个域名可以正常访问,前两个又不行了。
你的IIS CORS模块配置是这样的:
<cors enable="true" failUnlistedOrigins="true"> <add origin="https://www.first_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.second_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.third_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> </cors>
问题根源
这完全是IIS CORS模块的默认缓存机制在搞鬼!它会把第一次请求匹配到的Access-Control-Allow-Origin值缓存4分钟(默认的缓存时长),在缓存有效期内,不管后续请求来自哪个已授权域名,服务器都会直接返回缓存的那个Origin值,自然就被浏览器的跨域策略给拦下来了。
解决办法
针对这个问题,有两种靠谱的解决方案,你可以根据自己的场景选:
1. 直接禁用CORS缓存
在<cors>节点里加上cacheResponses="false"属性,这样服务器就会为每个请求动态匹配对应的Origin,不再缓存之前的结果:
<cors enable="true" failUnlistedOrigins="true" cacheResponses="false"> <add origin="https://www.first_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.second_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.third_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> </cors>
这个方案最简单直接,适合请求量不是特别大的场景,不会有缓存冲突的问题。
2. 配置Vary头实现多Origin缓存
如果你想保留缓存来提升性能,可以加上varyOrigin="true"属性,这样服务器会根据Origin请求头来区分缓存条目,同时返回Vary: Origin头告诉浏览器和中间缓存(比如CDN)要按Origin来缓存不同的响应:
<cors enable="true" failUnlistedOrigins="true" varyOrigin="true"> <add origin="https://www.first_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.second_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> <add origin="https://www.third_domain.com" allowed="true"> <allowHeaders allowAllRequestedHeaders="true" /> </add> </cors>
注意:如果你的图片前面还有CDN,得确保CDN也支持Vary: Origin头,不然CDN的缓存还是会出问题。
小提醒
别忘了修正JS代码里的语法错误,不然跨域请求根本没法正常发起哦!
内容的提问来源于stack exchange,提问作者Mark A. Durham

