Chrome, AWS S3 and CORS
- Web
- 20 Jun, 2021
前陣子與公司的其他夥伴一起找出了偶發的 CORS 原因,紀錄一下
如果一個網站內有包含對同一個 URL 的載入,但是有兩種方式,一種是從 HTML document 載入,另一種是用 xhr 存取,並且 Chome 有開啟 cache,就有可能會遇到。
重現問題
例如下面這個簡單的範例,用兩種方式從 AWS cloudfont 抓取圖片,CDN 的來源是 AWS S3
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<img src="https://someawscdn.cloudfront.net/image.png">
<script>
setTimeout(function () {
var oReq = new XMLHttpRequest();
oReq.open("GET", "https://someawscdn.cloudfront.net/image.png");
oReq.send();
}, 5000);
</script>
</body>
</html>
重現方式:
- 打勾 Disable cache
- 重新整理
- 在 xhr 發出請求前把 Disable cache 取消勾選
備註:雖然 xhr 顯示在第一個,但其實是後面才發生的
原因
會出問題是因為 chrome 把從 img tag 先載入的 response 結果 cache 著,接著讓 xhr 使用 cache 的 response 回應,而因為這個 response 沒有 CORS 需要的 Header:access-control-allow-methods、access-control-allow-origin,所以就發生 CORS error。
https://zhuanlan.zhihu.com/p/38972475 提到原因是 AWS S3 在 request Header 沒有帶 Origin 時(像是 img tag),回應的 Header 不會包含 Vary: Origin,所以沒辦法讓 chrome 去區別緊接而來有帶 Origin 的 request,是不能使用 cache 回應的。
解決方式
可以讓 xhr 的 URL 帶上額外參數,讓 xhr 跟 image tag 使用的 URL 不同就可以。例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<img src="https://someawscdn.cloudfront.net/image.png">
<script>
setTimeout(function () {
var oReq = new XMLHttpRequest();
oReq.open("GET", "https://someawscdn.cloudfront.net/image.png?cors=1");
oReq.send();
}, 5000);
</script>
</body>
</html>