背景
上線了新的業(yè)務(wù),域名是{cityId}.yy.com
,產(chǎn)品打算驗(yàn)收一下嘉栓,結(jié)果反饋好幾個(gè)同事先訪問https://sh.yy.com
之后切換到https://cd.yy.com
瀏覽的時(shí)候出現(xiàn)圖片加載不出來的情況永部。經(jīng)過排查發(fā)現(xiàn)是js沒加載成功導(dǎo)致懶加載沒生效,外在表現(xiàn)就是圖片沒加載成功亥至。控制臺(tái)報(bào)錯(cuò)如下:
交代下https://j1.cdn.com.cn/
域名下的資源是放在cdn上的靜態(tài)資源(資源每次上線會(huì)更新版本號(hào)贱迟,不會(huì)緩存)姐扮,上線的網(wǎng)站域名如下https://cd.yy.com
、https://sh.yy.com
(三級(jí)域名是代表城市衣吠,前面cd代表成都茶敏,bj代表北京);
現(xiàn)象
當(dāng)前域名為https://cd.yy.com
蒸播,打開Network睡榆;
查看https://j1.cdn.com.cn/aa.js
請求返回值,袍榆,response headers
中access-control-allow-origin:https://sh.yy.com
胀屿。也就像控制臺(tái)的報(bào)錯(cuò)一樣,與當(dāng)前域名不一致導(dǎo)致跨域包雀。但是我們看請求的另外一個(gè)文件https://j1.cdn.com.cn/bb.js
宿崭,這個(gè)的access-control-allow-origin:https://cd.yy.com
及當(dāng)前域名,bb.js
文件請求就沒有任何問題才写。
疑問
1.為什么我這邊幾個(gè)開發(fā)的電腦都沒有這種問題葡兑,但是產(chǎn)品卻大概率有這問題,有時(shí)候刷新就恢復(fù)正常了赞草?
2.為什么https://j1.cdn.com.cn/aa.js
的response headers
中的域名不是當(dāng)前域名讹堤?
3.為什么同樣是j1.cdn.com.cn
域名下兩個(gè)文件(aa.js和bb.js)的access-control-allow-origin
卻不一樣?
猜測
通過bug出現(xiàn)反饋的操作流程和報(bào)錯(cuò)信息來看厨疙,應(yīng)該是cdn資源被緩存住了洲守。由于開發(fā)這邊每次看問題常年喜歡打開控制臺(tái)而且勾上disable cache
,所以每次請求都沒有走瀏覽器的緩存沾凄。將disable cache
取消并且進(jìn)行切換域名操作果然復(fù)現(xiàn)了梗醇。那么其他疑問產(chǎn)生了。
疑問4:為什么瀏覽器的disable cache
項(xiàng)可以影響到后端返回的response headers
,以至于資源無法加載撒蟀?
疑問5:還是說這個(gè)請求所謂的response headers
是由于資源請求有問題叙谨,瀏覽器自身機(jī)制直接取上次的值呢?
通過在iTerm執(zhí)行命令行 curl -IL https://j1.cdn.com.cn/aa.js
保屯,可以看到response headers
中的access-control-allow-origin
確實(shí)是https://sh.yy.com
,說明疑問5中的說法不成立手负,response headers
確實(shí)是服務(wù)器端返回的涤垫。
那么我們看一下這個(gè)資源請求方式有什么不同:
看到了個(gè)后來加入的屬性crossorigin="anonymous"
,添加這個(gè)屬性是因?yàn)橐肓吮O(jiān)控系統(tǒng)虫溜,通過這個(gè)屬性可以獲取到資源內(nèi)部詳細(xì)的報(bào)錯(cuò)信息雹姊。對(duì)這個(gè)屬性不熟悉的可以參考這里股缸。
實(shí)踐
有了以上猜測之后隨即移除了aa.js
等一切js靜態(tài)資源的crossorigin
屬性衡楞,移除之后發(fā)現(xiàn)靜態(tài)資源可以正常加載,查看下詳細(xì)的網(wǎng)絡(luò)請求返回的字段敦姻;
1.https://j1.cdn.com.cn/aa.js
請求返回值response headers
中access-control-allow-origin:https://sh.yy.com
瘾境。
2.https://j1.cdn.com.cn/bb.js
請求返回值response headers
中access-control-allow-origin:https://cd.yy.com
。
和報(bào)錯(cuò)時(shí)候返回的一致镰惦,但是瀏覽器并沒有再報(bào)錯(cuò)了迷守,資源可以正常請求;
結(jié)論
由于cdn根據(jù)資源路徑緩存了response里面的內(nèi)容旺入,當(dāng)我們在不同域名下請求相同資源的時(shí)候就會(huì)出現(xiàn)域名不一致的問題兑凿;如果標(biāo)簽中添加了crossorigin="anonymous"
屬性,那么跨域請求的時(shí)候就會(huì)判斷是否同源茵瘾,如果不是同源的話礼华,請求將會(huì)報(bào)錯(cuò)并無法正常處理response。
Q&A
在此拗秘,我們來一一解答下上面的疑問圣絮,找到答案的小伙伴這里可以略過啦;
Q1:為什么我這邊幾個(gè)開發(fā)的電腦都沒有這種問題雕旨,但是產(chǎn)品卻大概率有這問題扮匠?
A1:開發(fā)的時(shí)候會(huì)勾選disable cache
,此時(shí)瀏覽器將不會(huì)走本地緩存凡涩。產(chǎn)品的電腦一般都沒有進(jìn)行勾選棒搜,所以當(dāng)切換域名時(shí),請求的還都是從本地緩存中的資源活箕,response header等其他數(shù)據(jù)也都是之前緩存過的力麸,所以當(dāng)使用資源使用crossorigin屬性,就會(huì)報(bào)錯(cuò)讹蘑。
Q2:為什么https://j1.cdn.com.cn/aa.js
的response headers
中的域名不是當(dāng)前域名末盔?
A2:綜上,因?yàn)閏dn緩存住了請求https://j1.cdn.com.cn/aa.js
的內(nèi)容及response headers等
信息座慰;
Q3:為什么同樣是j1.cdn.com.cn
域名下兩個(gè)文件(aa.js和bb.js)的access-control-allow-origin
卻不一樣陨舱?
A3:綜上,因?yàn)檫@兩個(gè)請求的資源是由不同的cdn返回的版仔,所以緩存的內(nèi)容也不一致游盲,查看response header 可以看到误墓,aa.js是x-via: DIANXIN-TIANJIN_41(200:miss);DIANXIN-TIANJIN_39(200:hit)
,bb.js是x-via: DIANXIN-TIANJIN_41(200:hit)
Q4:為什么瀏覽器的disable cache
項(xiàng)可以影響到后端返回的response headers
,以至于資源無法加載?
A4:并不是影響到了后端的返回益缎,而是瀏覽器的機(jī)制谜慌。當(dāng)查看到設(shè)置了crossorigin屬性且請求返回值的access-control-allow-origin
與當(dāng)前域名不一致后拋出了錯(cuò)誤,不再進(jìn)行進(jìn)一步渲染等操作莺奔;
Q5:這個(gè)瀏覽器所謂的response headers
是由于資源請求有問題欣范,瀏覽器自身機(jī)制直接取上次的值呢?
A5:這個(gè)上面有寫到令哟,使用curl或者抓包工具恼琼,可以看到后端返回的就是控制臺(tái)network展示的這些信息。