π 리μμ€ μΊμλ‘ μΈν CORS μλ¬ νμ κ³ μ°°
λΈλΌμ°μ μΊμλ‘ μΈν CORS λ¬Έμ
CORS(Cross-Origin Resource Sharing)λ μλ‘ λ€λ₯Έ μΆμ²(Origin)μ 리μμ€λ₯Ό 곡μ νκ³ μΆμλ μ¬μ©νλ μ μ± μ λ§νλ€.
κΈ°λ³Έμ μΌλ‘ λΈλΌμ°μ λ SOP(Same Origin Policy) μ μ± μ λ°λ₯΄κΈ° λλ¬Έμ μΈλΆ 리μμ€μ λν΄μ μ°¨λ¨νλ€. νμ§λ§ μΈν°λ·μ μ¬λ¬ μ¬λλ€μκ² μ€νλ νκ²½μ΄κ³ , μ΄λ° νκ²½μμ μΉνμ΄μ§μμ λ€λ₯Έ μΆμ²μ μλ 리μμ€λ₯Ό κ°μ Έμ μ¬μ©νλ μΌμ λ§€μ° νν μΌμ΄λΌ λͺ¨λ μΈλΆ 리μμ€λ₯Ό 무ν±λκ³ λ§μΌλ©΄ μ§κΈμ²λΌ μΉμ΄ λ°μ νμ§ μμμ κ²μ΄λ€. λ°λΌμ μΈλΆ 리μμ€λΌλ νμ© κ°λ₯ν μμΈ μ¬νμ λμλλ° κ·Έκ²μ΄ CORS μ μ± μ΄λ€.
μμ² λ°©μμ λ°λΌ λ€λ₯Έ CORS λ°μ μ¬λΆ
μ΄λ λΈλΌμ°μ λ HTTP μμ²μ λν΄μ μ΄λ€ λ°©μμΌλ‘ μμ²μ νλλμ λ°λΌ CORSλ₯Ό μλμΌλ‘ νμ©νκΈ°λ λ§κΈ°λ νλ€. μλ₯Όλ€μ΄ <img> νκ·Έμ κ°μ μΈλΌμΈμΌλ‘ 리μμ€λ₯Ό μμ²νλ©΄ λ€λ₯Έ μΆμ²μ 리μμ€λΌλ κ²μ¬ μμ΄ μλ ν΅κ³Όλλ€. κ·Έλ¬λ μλ°μ€ν¬λ¦½νΈ Ajax μμ²μΌ κ²½μ° μ΄κΉμμ΄ μ°¨λ¨λμ΄ λ²λ¦°λ€.
μμ² λ°©μμ λ°λΌ λ€λ₯Έ CORS λ°μ μ¬λΆλ₯Ό μ’ λ μ΄ν΄νκΈ° μ½κ² μλ html μ½λλ₯Ό μ§μ μμ±νκ³ ν μ€νΈ ν΄λ³΄μ. λκ°μ μλ² λλ©μΈμΌλ‘ λΆν° check.svg μ΄λ―Έμ§λ₯Ό κ°μ Έμ€μ§λ§ κ²°κ³Όλ λ€λ₯΄κ² λλ€.
β» μ°Έκ³ λ‘ ν΄λΉ νΈμ€ν μλ²λ cors μ€μ μ΄ λμ΄μμ§ μλ μλ²λΌκ³ κ°μ ν΄λ³΄μ.
<img src="https://third-party-test.glitch.me/check.svg" alt="μ΄λ―Έμ§">
<script>
fetch('https://third-party-test.glitch.me/check.svg')
.then(response => response.blob())
.then(imgBlob => {
const imageObjectURL = URL.createObjectURL(imgBlob); // μλ΅ λ°μ μ΄λ―Έμ§λ₯Ό blob κ°μ²΄λ‘ λ³ν
const img = document.createElement('img'); // μ΄λ―Έμ§ νκ·Έλ₯Ό μμ±νκ³
img.src = imageObjectURL; // μ΄λ―Έμ§ κ²½λ‘λ₯Ό μ€μ νλ€
document.body.append(img); // htmlμ μΆκ°
})
</script>
νμ΄μ§ κ²°κ³Όλ₯Ό 보면 μ΄λ―Έμ§κ° νλλ§ λνλλ κ±Έ λ³Ό μ μμ κ²μ΄λ€.
λΈλΌμ°μ κ°λ°μ λꡬμ Network μ°½μ 보면 check.svg μ΄λ―Έμ§μ λν΄μ λλ² μμ²μ νμ§λ§ μλ°μ€ν¬λ¦½νΈ fetch TypeμΌλ‘ μμ²ν κ²μ΄ Statusκ° CORS error μμ λ³Όμκ° μλ€.
fetch μμ² μ²λ¦¬μ λν ν€λ λͺ©λ‘μ 보면 κ·Έ μ΄μ λ₯Ό μ μ μλλ°, ν΄λΌμ΄μΈνΈκ° μμ μ Originμ μμ² ν€λμ λ£μ΄ μλ²μ μ λ¬νμ§λ§, μλ²μμ λ³λ€λ₯Έ μ‘μ
μμ΄ Access-Control-Allow-Origin ν€λλ₯Ό μλ΅ν΄μ£Όμ§ μμκ³ , μ΄λ₯Ό λΈλΌμ°μ κ° κ°μ§νμ¬ μ¬λ¨μ μ°¨λ¨ν κ²μ΄λ€. μ¬κΈ°μ μ€ν΄νμ§ λ§μμΌ ν μ μ΄ μλ²λ 리μμ€λ₯Ό μ μ μλ΅νμ§λ§ λΈλΌμ°μ κ° cors κ΄λ ¨ ν€λ μλ€κ³ μ°¨λ¨ν΄ λ²λ¦° κ²μ΄λ€.
λ°λ©΄ λΈλΌμ°μ λ <img>, <video> μ κ°μ μΌλΆ λ―Έλμ΄ νκ·Έλ₯Ό ν΅ν΄ 리μμ€λ₯Ό μμ²ν CORSλ₯Ό μ ννμ§ μλλ€.κ·Έλμ HTTP μμ²μ Origin ν€λλ₯Ό μΆκ°νμ§ μκ³ , λΈλΌμ°μ λ λ³λ€λ₯Έ κ²μ¬ μμ΄ ν΅κ³Όνκ² ν΄μ£Όλ κ²μ΄λ€.
μΊμμ μ μ₯λ 리μμ€λ₯Ό κ·Έλλ‘ λΆλ¬μ¬ κ²½μ°
κ·Έλ°λ° μ΄ CORSλ₯Ό μ ννμ§ μκ³ λ°μ 리μμ€λ₯Ό λΈλΌμ°μ κ° λ‘컬 μΊμμ μ μ₯νκ³ μ¬νμ© ν κ²½μ° λ¬Έμ κ° λ°μνκ² λλ€.
μλ₯Ό λ€μ΄ μλμ κ°μ΄ μ΄λ―Έμ§λ₯Ό μμ² ν κ²½μ° λ¬Έμ μμ΄ μλ²λ‘ λΆν° μΈλΆ 리μμ€λ₯Ό λ°λλ€.
β» μ°Έκ³ λ‘ ν΄λΉ νΈμ€ν μλ²λ cors μ€μ μ΄ λμ΄μλ μλ²μ΄κΈ° λλ¬Έμ μλ°μ€ν¬λ¦½νΈ ajax μμ²μλ μ μμ μΌλ‘ μλ΅νκ² λλ€.
<img src="https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png" alt="μ΄λ―Έμ§">
<script>
fetch('https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png', { mode: 'cors' })
.then(response => response.blob())
.then(imgBlob => {
const imageObjectURL = URL.createObjectURL(imgBlob);
const img = document.createElement('img');
img.src = imageObjectURL;
document.body.append(img);
})
</script>
μ΄λ²μλ μλ°μ€ν¬λ¦½νΈ fetch μμ²μ 3μ΄ λ€μ νλΌκ³ setTimeout() λ©μλλ₯Ό ν΅ν΄ μ€μ ν΄λ³΄μ. μ΄λ κ² νλ μ΄μ λ μ΄λ―Έμ§ νκ·Έλ‘ μμ²ν sample.png μ΄λ―Έμ§κ° λΈλΌμ°μ λ‘컬 μΊμμ μ μ₯νλλ‘ μκ°μ μ£ΌκΈ° μν΄μ μ΄λ€. κ·Έλ¬λ©΄ 3μ΄ λ€μ λκ°μ μ΄λ―Έμ§ URLμ μμ²ν κ²½μ° λΈλΌμ°μ λ μλμΌλ‘ μ΅μ νλ₯Ό μν΄ μλ²μ μμ²μ λ리λ κ²μ΄ μλ μΊμ μ μ₯μμμ 리μμ€λ₯Ό κ°μ Έμ€κ² λλ€.
<img src="https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png" alt="μ΄λ―Έμ§">
<script>
setTimeout(() => {
fetch('https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png', { mode: 'cors' })
.then(response => response.blob())
.then(imgBlob => {
const imageObjectURL = URL.createObjectURL(imgBlob);
const img = document.createElement('img');
img.src = imageObjectURL;
document.body.append(img);
})
}, 3000);
</script>
κ·Έλ°λ° κ²°κ³Όλ CORS μλ¬κ° λ¬λ€. λΆλͺ
μλ²μμ λͺ¨λ μΆμ²λ₯Ό νμ©νλ access-control-allow-origin: * ν€λλ₯Ό μ€μ νμκ³ , setTimeout() λ©μλλ₯Ό μ κΉμ§λ λ¬Έμ μμ΄ μ λ°μμλλ° λ§μ΄λ€.
리μμ€μ λν μμ² / μλ΅ ν€λλ₯Ό 보면 μ κ·Έλ°μ§μ λν μ μΆκ° κ°λ₯νλ€.
μμ λ§νλ―μ΄ <img> νκ·Έλ‘ λΆλ¬μ€λ μΈλΌμΈ 리μμ€ μμ²μΌ κ²½μ°μ μμ² ν€λμλ Origin ν€λκ° μλ€. λ°λΌμ μλ²μμλ Access-Control-Allow-Origin ν€λλ₯Ό μ€μ΄ 보λ΄μ§ μκ²λκ³ , μ΄ μν κ·Έλλ‘ μΊμμ μ μ¬λκ² λλ€.
κ·Έλ¦¬κ³ 3μ΄ λ€μ λκ°μ 리μμ€ URLμ μμ²νμλ μΊμ μ μ₯μμ μλ 리μμ€λ₯Ό κ°μ Έμ€λλ°, μλ΅ ν€λμ Access-Control-Allow-Origin ν€λκ° μκΈ° λλ¬Έμ μλμ κ°μ΄ No ' Access-Control-Allow-Origin' header λΌκ³ μλ¬ λ©μΈμ§λ₯Ό λ΄λΏλ κ²μ΄λ€.
μΊμλ‘ μΈν CORS μλ¬ ν΄κ²°λ°©λ²
crossorigin μμ± ν λΉνμ¬ κ°μ CORS κ²μ¬ ννκΈ°
ν΄κ²° λ°©λ²μ μλμ κ°μ΄ <img> νκ·Έμ μμ±μΌλ‘ crossorigin μ ν λΉν΄ μ£Όλ©΄ λλ€.
<img crossorigin src="https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png" alt="μ΄λ―Έμ§">
<script>
setTimeout(() => {
fetch('https://tistory4.daumcdn.net/tistory/5927418/skin/images/sample.png', { mode: 'cors' })
.then(response => response.blob())
.then(imgBlob => {
const imageObjectURL = URL.createObjectURL(imgBlob);
const img = document.createElement('img');
img.src = imageObjectURL;
document.body.append(img);
})
}, 3000);
</script>
crossorigin μμ±
<audio> , <img> , <link> , <script> λ° <video> μ κ°μ λ―Έλμ΄ μμ μ crossorigin μμ±μ μμκ° κ΅μ°¨ μΆμ² μμ²μ μ²λ¦¬νλ λ°©λ²μ μ μνλ μμ±μ΄λ€. 보ν΅μ ν΄λΌμ΄μΈνΈμμ μΏ ν€λ μΈμ¦ ν€λλ₯Ό μ€μ΄ μλ²μ 보λΌλ μ¬μ©λλ μμ±μ΄μ§λ§, μ΄κ²μ νκ·Έ μμ±μΌλ‘ λͺ
μνλ©΄ μΈλΌμΈ 리μμ€ μμ²μ΄λ λλ κ°μ μ μΌλ‘ CORS μ μ±
μ λ°λ₯΄κ² νμ¬ λ¦¬μμ€μ λν μμΈμ€ κΆνμ μμ²νκ² νλ€.
κ°λ°μ λꡬμ ν€λ λͺ©λ‘μ 보면 λ κ°μ΄ μ‘ν κ²μ΄λ€. λΉλ‘ μΈλΌμΈ 리μμ€ μμ²μ΄μ§λ§ μμ² ν€λμ Origin ν€λκ° λ΄κΈ΄κ±Έ λ³Ό μ μκ³ μλ²λ μ΄μ λ°μνμ¬ cors ν€λλ₯Ό μλ΅ν¨μ λ³Ό μ κ° μλ€.
λ°λΌμ 3μ΄ λ€μ νν΄μ§λ§ μλ°μ€ν¬λ¦½νΈ Ajax μμ² μμ μΊμμ 리μμ€λ₯Ό κ°μ Έμ€λλΌλ, μ΄λ―Έ μΊμ μ μ₯μμ μλ 리μμ€λ Access-Control-Allow-Origin ν€λκ° μ€μ λ 리μμ€ μ΄κΈ° λλ¬Έμ CORS κ΄λ¬Έ κ²μ¬μ ν΅κ³Όλλ κ²μ΄λ€.
crossorigin μμ±μ΄ μλλ° μλ² CORS νμ©μ΄ μλ κ²½μ°
λ°λλ‘ λ§μΌ μλ²μμ λ³λ€λ₯Έ cors ν€λ μ€μ μ νμ§ μμμ κ²½μ° <img crossorigin src> μΈλΌμΈ μμ²λ κ²°κ΅ cors μλ¬ λ‘κ·Έκ° λνλκ² λλ€. μλνλ©΄ crossorigin μμ±μ κ°μ λ‘ CORS κ²μ¬ κ΄λ¬Έμ ννκΈ° λλ¬Έμ΄λ€.
μ 리νμλ©΄, μλ²μ Origin νμ©μ΄ λ μνμμ λμΌν 리μμ€μ λν μ€λ³΅ μμ²μ corsλ₯Ό ν΅ν΄ κ°μ Έμ¬ κ²½μ° μμ μκ°λ¦Όμ μ‘°μ¬νλ©΄ λλ€. λν λΈλΌμ°μ λ‘컬 μΊμ λΏλ§ μλλΌ μ΄λ°μλ νλ‘μ(Proxy)λ CloudFrontμ κ°μ CDN μλΉμ€λ₯Ό μ΄μ©ν λλ CORS μΊμ λ¬Έμ κ° λ°λΌμ€κ² λλ€. λ³΄ν΅ ν΄λΌμ°λμ CDN μλΉμ€μΌ κ²½μ° μ΄λ¬ν κ²½μ°λ₯Ό λλΉν΄ λ³λλ‘ Cache Key μ€μ μ μ 곡νλ μ΄μ λν΄μ κ²μν΄λ³΄κΈΈ λ°λλ€.