êµì°¨ ì¶ì² 리ìì¤ ê³µì (CORS)
Baseline
Widely available
This feature is well established and works across many devices and browser versions. Itâs been available across browsers since 2015ë 7ì.
êµì°¨ ì¶ì² 리ìì¤ ê³µì (Cross-Origin Resource Sharing, CORS)ë ë¸ë¼ì°ì ê° ìì ì ì¶ì²ê° ìë ë¤ë¥¸ ì´ë¤ ì¶ì²(ëë©ì¸, ì¤í´ í¹ì í¬í¸)ë¡ë¶í° ììì ë¡ë©íë ê²ì íì©íëë¡ ìë²ê° íê° í´ì£¼ë HTTP í¤ë ê¸°ë° ë©ì»¤ëì¦ì ëë¤. ëí CORS ë êµì°¨ ì¶ì² 리ìì¤ë¥¼ í¸ì¤í íë ìë²ê° ì¤ì ìì²ì íê°í ê²ì¸ì§ íì¸í기 ìí´ ë¸ë¼ì°ì ê° ë³´ë´ë "ì¬ì ìì²(í리íë¼ì´í¸, Preflight)" ë©ì»¤ëì¦ì ìì¡´í©ëë¤. ì´ ì¬ì ìì²ìì ë¸ë¼ì°ì ë ì¤ì ìì²ìì ì¬ì©í HTTP ë©ìëì í¤ëë¤ì ëí ì ë³´ê° íìë í¤ëì ë´ì ë³´ë ëë¤.
êµì°¨ ì¶ì² ìì²ì ìì: https://domain-a.com ìì ì ê³µëë íë¡ í¸ìë JavaScript ì½ëê° fetch()를 ì¬ì©íì¬ https://domain-b.com/data.json ì ìì²íë ê²½ì°.
ë³´ììì ì´ì ë¡ ë¸ë¼ì°ì ë ì¤í¬ë¦½í¸ìì ììí êµì°¨ ì¶ì² HTTP ìì²ì ì íí©ëë¤. ì를 ë¤ì´, fetch() ì XMLHttpRequest ë ëì¼ ì¶ì² ì ì±
ì ë°ë¦
ëë¤. ì´ë ì´ë¬í API를 ì¬ì©íë ì¹ ì í리ì¼ì´ì
ì´ ì í리ì¼ì´ì
ì´ ë¡ëë ëì¼í ì¶ì²ììë§ ë¦¬ìì¤ë¥¼ ìì²í ì ìì¼ë©°, ë¤ë¥¸ ì¶ì²ì ìëµì ì¬ë°ë¥¸ CORS í¤ëê° í¬í¨ëì´ ìì§ ìë í ê·¸ë ì§ ëª»íë¤ë ê²ì ì미í©ëë¤.
CORS ë©ì»¤ëì¦ì ë¸ë¼ì°ì ì ìë² ê°ì ìì í êµì°¨ ì¶ì² ìì² ë° ë°ì´í° ì ì¡ì ì§ìí©ëë¤. ë¸ë¼ì°ì ë êµì°¨ ì¶ì² HTTP ìì²ì ìíì ìíí기 ìí´ fetch() ë XMLHttpRequest ê°ì APIìì CORS를 ì¬ì©í©ëë¤.
ì´ë¤ ìì²ì´ CORS를 ì¬ì©í©ëê¹?
ì´ êµì°¨ ì¶ì² ê³µì íì¤ì ë¤ìê³¼ ê°ì ê²½ì°ì êµì°¨ ì¶ì² HTTP ìì²ì ê°ë¥íê² í©ëë¤.
- ììì ì¸ê¸í
fetch()ëëXMLHttpRequestì í¸ì¶. - ì¹ í°í¸(CSS ë´
@font-faceìì êµì°¨ ëë©ì¸ í°í¸ ì¬ì© ì), ìë²ê° êµì°¨ ì¶ì²ë¡ë§ ë¡ëë ì ìê³ íê°ë ì¹ì¬ì´í¸ììë§ ì¬ì©í ì ìë True Type í°í¸ë¥¼ ë°°í¬í ì ìê² í©ëë¤. - WebGL í ì¤ì³.
drawImage()를 ì¬ì©í´ ìºë²ì¤ì 그린 ì´ë¯¸ì§/ë¹ëì¤ íë ì.- ì´ë¯¸ì§ë¡ë¶í° ì¶ì¶íë CSS Shapes.
êµì°¨ ì¶ì² 리ìì¤ ê³µì ì ëí ì¼ë°ì ì¸ ê¸ì´ë©° íìí HTTP í¤ëì ëí ë ¼ìë í¬í¨íê³ ììµëë¤.
기ë¥ì ê°ì
êµì°¨ ì¶ì² 리ìì¤ ê³µì íì¤ì ìë²ê° ì¹ ë¸ë¼ì°ì ìì í´ë¹ ì 보를 ì½ë ê²ì´ íì©ë ì¶ì²ë¥¼ ì¤ëª
í ì ìëë¡ ìë¡ì´ HTTP í¤ë를 ì¶ê°í¨ì¼ë¡ì¨ ëìí©ëë¤. ì¶ê°ì ì¼ë¡, ìë² ë°ì´í°ì ë¶ì í¨ê³¼(side effect)를 ì¼ì¼í¬ ì ìë HTTP ìì² ë°©ë²(í¹í GET ì´ì¸ì HTTP ë©ìë ëë í¹ì MIME íì
ì ì¬ì©íë POST)ì ëí´ì, CORS ëª
ì¸ë ë¸ë¼ì°ì ê° HTTP OPTIONS ë©ìëë¡ ìë²ìì ì§ìíë ë©ìëë¤ì ì구íë ìì²ì "ì¬ì ì ë¬(í리íë¼ì´í¸)"í ë¤ì, ìë²ë¡ë¶í° "ì¹ì¸"ì ë°ì í ì¤ì ìì²ì ë³´ë´ëë¡ ì§ìí©ëë¤. ëí ìë²ë ìì²ê³¼ í¨ê» "ì격 ì¦ëª
"(ì를 ë¤ì´ ì¿ í¤ ë° HTTP ì¸ì¦)ì ì ì¡í´ì¼ íëì§ ì¬ë¶ë¥¼ í´ë¼ì´ì¸í¸ìê² ì릴 ì ììµëë¤.
CORS ì¤í¨ë ì¤ë¥ë¥¼ ë°ììí¤ì§ë§, ë³´ììì ì´ì ë¡ ì¤ë¥ì ëí ì¸ë¶ ì¬íì JavaScriptì ì ê³µëì§ ììµëë¤. ì½ëê° ì ì ìë ê²ì ì¤ë¥ê° ë°ìíë¤ë ê²ë¿ì ëë¤. 무ìì´ êµ¬ì²´ì ì¼ë¡ ì못ëìëì§ë¥¼ íì¸íë ¤ë©´ ë¸ë¼ì°ì ì ì½ììì ì¸ë¶ ì¬íì ì´í´ë´ì¼ í©ëë¤.
ë¤ì ì¹ì ììë ë¤ìí ìë리ì¤ë¥¼ ë ¼ìíê³ , ì¬ì©ëë HTTP í¤ëì ëí ì¸ë¶ ì¬íì ì ê³µí©ëë¤.
ì ê·¼ ì ì´ ìëë¦¬ì¤ ìì
êµì°¨ ì¶ì² 리ìì¤ ê³µì ê° ëìíë ë°©ìì ë³´ì¬ì£¼ë ì¸ ê°ì§ ìë리ì¤ë¥¼ ì ìíê² ìµëë¤. 모ë ìì ë ì§ìíë ë¸ë¼ì°ì ìì êµì°¨ ì¶ì² ìì²ì ìì±í ì ìë fetch()를 ì¬ì©í©ëë¤.
ë¨ì ìì²(Simple requests)
ì¼ë¶ ìì²ì CORS ì¬ì ìì²ì í¸ë¦¬ê±°íì§ ììµëë¤. ì´ë¬í ìì²ì 구ì CORS ì¬ìììë "ë¨ì ìì²"ì´ë¼ê³ ë¶ë ¸ì¼ë, íì¬ CORS ì ìíë Fetch ì¬ìììë ì´ ì©ì´ë¥¼ ì¬ì©íì§ ììµëë¤.
ì´ë¬í ë기ë HTML 4.0ì <form> ìì(êµì°¨ ì¬ì´í¸ fetch() ì XMLHttpRequest ë³´ë¤ ì´ì ì ì¡´ì¬í ìì)ê° ì´ë¤ ì¶ì²ë¡ë ë¨ì ìì²ì ì ì¶í ì ìë¤ë ê²ì
ëë¤. ë°ë¼ì ìë² ì°ê¸°ë¥¼ ìííë 모ë ì¬ëì ì´ë¯¸ ì¬ì´í¸ ê° ìì² ìì¡°(Cross Site Request Forgery, CSRF)ë¡ë¶í° ë³´í¸íê³ ìì´ì¼ í©ëë¤. ì´ë¬í ê°ì íìì, CSRF ì ìíì í¼ ì ì¶ì ìíê³¼ ë¤ë¥´ì§ ì기 ë문ì ìë²ë í¼ ì ì¶ì²ë¼ ë³´ì´ë ìì²ì ë°ê¸° ìí´ ì¬ì ìì²ì ìëµíë ìµí¸-ì¸(opt-in)ì í íìê° ììµëë¤. ê·¸ë¬ë ìë²ë ì¬ì í Access-Control-Allow-Origin ì ì¬ì©íì¬ ì¤í¬ë¦½í¸ì ìëµì ê³µì íëë¡ ìµí¸-ì¸ í´ì¼ í©ëë¤.
ë¨ì ìì²ì ë¤ì ì¡°ê±´ì 모ë 충족íë ìì²ì ëë¤.
-
ë¤ì ì¤ íëì ë©ìë
-
ì¬ì©ì ìì´ì í¸ê° ìëì¼ë¡ ì¤ì í í¤ë(ì를 ë¤ì´,
Connection,User-Agent, Fetch ëª ì¸ìì "forbidden header name"ì¼ë¡ ì ìí í¤ë) ì¸ì, ìëì¼ë¡ ì¤ì í ì ìë í¤ëë ì¤ì§ Fetch ëª ì¸ìì "CORS-safelisted request-header"ë¡ ì ìí í¤ë ë¿ì ëë¤.AcceptAccept-LanguageContent-LanguageContent-Type(ìëì ì¶ê° ì구 ì¬íì ì ìíì¸ì.)Range(ì¤ì§ ë¨ì ë²ì í¤ë ê°, ì를 ë¤ì´bytes=256-í¹ìbytes=127-255)
-
Content-Typeí¤ëì ì§ì ë 미ëì´ íì ì ëí´ íì©ë íì /ìë¸íì ì¡°í©ì ë¤ìê³¼ ê°ìµëë¤.application/x-www-form-urlencodedmultipart/form-datatext/plain
-
ìì²ì´
XMLHttpRequestê°ì²´ë¥¼ ì¬ì©íì¬ ì´ë£¨ì´ì§ ê²½ì°, ìì²ì ì¬ì©ëXMLHttpRequest.uploadìì±ì ìí´ ë°íë ê°ì²´ì ì´ë²¤í¸ 리ì¤ëê° ë±ë¡ëì§ ììµëë¤. ì¦,XMLHttpRequestì¸ì¤í´ì¤xhrì´ ìë¤ë©´ ì ë¡ë를 모ëí°ë§í기 ìí ì´ë²¤í¸ 리ì¤ë를 ì¶ê°íëxhr.upload.addEventListener()를 í¸ì¶íë ì½ëê° ì¡´ì¬íì§ ìëë¤ë ê²ì ëë¤. -
ìì²ì
ReadableStreamê°ì²´ê° ì¬ì©ëì§ ììµëë¤.
ì°¸ê³ : WebKit Nightly ì Safari Technology Preview ë Accept, Accept-Language, Content-Language í¤ëì íì©ëë ê°ì ì¶ê°ì ì¸ ì ì½ì ê°í©ëë¤. ì´ë¬í í¤ë ì¤ íëë¼ë "ë¹íì¤" ê°ì ê°ë ê²½ì°, WebKit/Safari ë í´ë¹ ìì²ì "ë¨ì ìì²"ì¼ë¡ ê°ì£¼íì§ ììµëë¤. WebKit/Safari ìì ì´ë¤ ê°ì "ë¹íì¤"ì¼ë¡ ê°ì£¼íëì§ë ë¤ìì WebKit ë²ê·¸ ì¸ìë 문ìíëì´ ìì§ ììµëë¤:
- Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language
- Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS
- Switch to a blacklist model for restricted Accept headers in simple CORS requests
ì´ ë¶ë¶ì CORS ëª ì¸ê° ìë기 ë문ì ë¤ë¥¸ ë¸ë¼ì°ì ìë ì´ë¬í ì¶ê° ì í ì¬íì´ ììµëë¤.
ì를 ë¤ì´ https://foo.exampleì ì¹ ì½í
ì¸ ê° https://bar.other ëë©ì¸ìì JSON ì½í
ì¸ ë¥¼ ê°ì ¸ì¤ê³ ì íë¤ê³ ê°ì í´ ë´
ìë¤. ì´ë¬í ì¢
ë¥ì ì½ëë foo.exampleì ë°°í¬ë JavaScriptìì ì¬ì©ë ì ììµëë¤.
const fetchPromise = fetch("https://bar.other");
fetchPromise
.then((response) => response.json())
.then((data) => {
console.log(data);
});
ì´ ìì ì í´ë¼ì´ì¸í¸ì ìë² ê°ì ê°ë¨í êµíì ìííë©°, ê¶í ì²ë¦¬ë¥¼ ìí´ CORS í¤ë를 ì¬ì©í©ëë¤.
ì´ ê²½ì° ë¸ë¼ì°ì ê° ìë²ë¡ ë³´ë´ë ë´ì©ì ì´í´ë³´ê² ìµëë¤.
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
주목í ìì² í¤ëë Origin ì¼ë¡, ìì²ì´ https://foo.example ìì ììì ëíë
ëë¤.
ì´ì ìë²ê° ì´ë»ê² ìëµíëì§ ì´í´ë³´ê² ìµëë¤.
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[â¦XML Dataâ¦]
ìë²ë Access-Control-Allow-Origin í¤ëì 모ë ì¶ì²ìì í´ë¹ 리ìì¤ì ì ê·¼í ì ììì ì미íë Access-Control-Allow-Origin: * ì ë°íí©ëë¤.
Access-Control-Allow-Origin: *
ì´ Origin ë° Access-Control-Allow-Origin í¤ë í¨í´ì ì ê·¼ ì ì´ íë¡í ì½ì ê°ì¥ ê°ë¨í ì¬ì©ë²ì
ëë¤. ë§ì½ https://bar.other ì 리ìì¤ ìì ìê° í´ë¹ 리ìì¤ì ì ê·¼ì ì¤ì§ https://foo.example ì¶ì²ìì ì¤ë ìì²(ì¦, https://foo.example ì´ì¸ì ëë©ì¸ììë êµì°¨ ì¶ì² ë°©ìì¼ë¡ í´ë¹ 리ìì¤ì ì ê·¼í ì ìì)ì¼ë¡ë§ ì íí길 ìíë¤ë©´ ë¤ìê³¼ ê°ì´ ìëµì ë³´ë¼ ê²ì
ëë¤.
Access-Control-Allow-Origin: https://foo.example
ì°¸ê³ : ì격 ì¦ëª ì´ í¬í¨ë ìì²ì ìëµí ë, ìë²ë Access-Control-Allow-Origin í¤ëì ê°ì¼ë¡ "*" ìì¼ëì¹´ë를 ì§ì íë ëì í¹ì ì¶ì²ë¥¼ ë°ëì ì§ì í´ì¼ í©ëë¤.
ì¬ì ìì²(Preflighted requests)
ë¨ì ìì²ê³¼ ë¬ë¦¬ "ì¬ì ì ì¡(preflighted)" ìì²ì ê²½ì° ì¤ì ìì²ì ë³´ë´ë ê²ì´ ìì íì§ íë¨í기 ìí´ ë¸ë¼ì°ì ê° ë¨¼ì OPTIONS ë©ìë를 ì¬ì©í´ ë¤ë¥¸ ì¶ì²ì 리ìì¤ì HTTP ìì²ì ë³´ë
ëë¤. ì´ë¬í êµì°¨ ì¶ì² ìì²ì ì¬ì©ì ë°ì´í°ì ìí¥ì ë¯¸ì¹ ì ì기 ë문ì ì¬ì ì ì ì¡ë©ëë¤.
ë¤ìì ì¬ì ìì²ì´ íìí ìì²ì ììì ëë¤.
const fetchPromise = fetch("https://bar.other/doc", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "text/xml",
"X-PINGOTHER": "pingpong",
},
body: "<person><name>Arun</name></person>",
});
fetchPromise.then((response) => {
console.log(response.status);
});
ì ìì ë POST ìì²ê³¼ í¨ê» ë³´ë¼ XML ë°ë를 ë§ëëë¤. ëí, ë¹íì¤ HTTP X-PINGOTHER ìì² í¤ëê° ì¤ì ë©ëë¤. ì´ë¬í í¤ëë HTTP/1.1ì ì¼ë¶ê° ìëì§ë§ ì¼ë°ì ì¼ë¡ ì¹ ì í리ì¼ì´ì
ì ì ì©í©ëë¤. ìì²ì´ Content-Type í¤ëì text/xml ì ì¬ì©íê³ , ì¬ì©ì ì§ì í¤ëê° ì¤ì ëì´ ì기 ë문ì ì´ ìì²ì ì¬ì ìì²ë©ëë¤.
ì°¸ê³ :
ìë ì¤ëª
í ë°ì ê°ì´ ì¤ì POST ìì²ìë Access-Control-Request-* í¤ëê° í¬í¨ëì§ ììµëë¤. ì´ í¤ëë¤ì ì¤ì§ OPTIONS ìì²ìë§ íìí©ëë¤.
í´ë¼ì´ì¸í¸ì ìë² ê°ì ì ì²´ íµì ì ì´í´ë³´ê² ìµëë¤. 첫 ë²ì§¸ íµì ì ì¬ì ìì²ê³¼ ê·¸ì ëí ìëµì ëë¤.
OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-pingother
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
ì 첫 ë²ì§¸ ë¸ë¡ì OPTIONS ë©ìë를 ì¬ì©í ì¬ì ìì²ì ëíë
ëë¤. ë¸ë¼ì°ì ë ì JavaScript ì½ë ì¤ëí«(snippet)ìì ì¬ì©í ìì² íë¼ë¯¸í°ë¥¼ 기ì¤ì¼ë¡ ì¬ì ìì²ì´ íìíë¤ê³ ê²°ì í©ëë¤. ì´ ì¬ì ìì²ì íµí´ ìë²ë ì¤ì ìì² íë¼ë¯¸í°ë¡ ìì²ì ë³´ë´ë ê²ì´ ì ì íì§ ìëµí ì ììµëë¤. OPTIONS ë ìë²ë¡ë¶í° ì¶ê° ì 보를 ì»ê¸° ìí´ ì¬ì©ëë HTTP/1.1 ë©ìëì´ë©° 리ìì¤ë¥¼ ë³ê²½í ì ìë ìì í ë©ìëì
ëë¤. OPTIONS ìì²ê³¼ í¨ê» ë ê°ì ë¤ë¥¸ ìì² í¤ëê° ì ì¡ë©ëë¤.
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-pingother
Access-Control-Request-Method í¤ëë ì¬ì ìì²ì ì¼ë¶ë¡ì¨ ìë²ìê² ì¤ì ìì²ì´ ì ì¡ë ë POST ìì² ë©ìë를 ì¬ì©í ê²ìì ì립ëë¤. Access-Control-Request-Headers í¤ëë ì¤ì ìì²ì´ ì ì¡ë ë ì¬ì©ì ì ì í¤ë X-PINGOTHER ì Content-Type 를 ì¬ì©í ê²ìì ìë²ìê² ì립ëë¤. ì´ì ìë²ë ì´ë¬í ì¡°ê±´ìì ìì²ì ìë½í ì ìëì§ ê²°ì í 기í를 ì»ê² ë©ëë¤.
ì ë ë²ì§¸ ë¸ë¡ì ìë²ê° ë°ííë ìëµì¼ë¡, ìì² ë©ìë(POST)ì ìì² í¤ë(X-PINGOTHER)ê° íì©ëë¤ë ê²ì ëíë
ëë¤. ì´ì´ì§ë ë´ì©ì ìì¸í ì´í´ë³´ê² ìµëë¤.
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
ìë²ë Access-Control-Allow-Origin: https://foo.example í¤ëë¡ ìëµíì¬ ìì²ì ë³´ë¸ ì¶ì² ëë©ì¸ë§ ì ê·¼ ê°ë¥íëë¡ ì íí©ëë¤. ëí Access-Control-Allow-Methods í¤ëë¡ ìëµíì¬ POST ì GET ë©ìëê° í´ë¹ 리ìì¤ë¥¼ ìì²íë ë° ì í¨í ë©ìëìì ëíë
ëë¤(ì´ í¤ëë Allow ìëµ í¤ëì ì ì¬íì§ë§, ì ê·¼ ì ì´ ë§¥ë½ ë´ìì ì격íê² ì¬ì©ë©ëë¤).
ìë²ë ëí Access-Control-Allow-Headers í¤ëì "X-PINGOTHER, Content-Type" ê°ì ì¤ì íì¬ ë³´ë´ ì´ í¤ëë¤ì´ ì¤ì ìì²ì ì¬ì©í ì ìë íì©ë í¤ëìì íì¸í´ ì¤ëë¤. Access-Control-Allow-Methods ì ë§ì°¬ê°ì§ë¡ Access-Control-Allow-Headers ë íì© ê°ë¥í í¤ëì ì¼íë¡ êµ¬ë¶í©ëë¤.
ë§ì§ë§ì¼ë¡, Access-Control-Max-Age ë ë ë¤ë¥¸ ì¬ì ìì²ì ë³´ë´ì§ ìëë¡ ì¬ì ìì²ì ëí ìëµì ì¼ë§ë ì¤ë«ëì ìºìí ì ìëì§ ì´ ë¨ì ìê° ê°ì ì ê³µí©ëë¤. 기본 ê°ì 5ì´ì
ëë¤. íì¬ ìµë ìºì ìê°ì 86400ì´(= 24ìê°)ì
ëë¤. ê° ë¸ë¼ì°ì ë Access-Control-Max-Age ê° ì´ë¥¼ ì´ê³¼í ë ì°ì ëë ìµë ë´ë¶ ê°ì ê°ì§ëë¤.
ì¬ì ìì²ì´ íë² ìë£ëë©´ ì¤ì ìì²ì´ ì ì¡ë©ëë¤.
POST /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache
<person><name>Arun</name></person>
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some XML payload]
ì¬ì ìì²ê³¼ 리ë¤ì´ë í¸
íì¬ ëª¨ë ë¸ë¼ì°ì ê° ì¬ì ìì² í 리ëë ì íë ê²ì ì§ìíì§ ììµëë¤. ì¬ì ìì² í 리ë¤ì´ë í¸ê° ë°ìíë©´ ì¼ë¶ ë¸ë¼ì°ì ë ë¤ìê³¼ ê°ì ì¤ë¥ ë©ìì§ë¥¼ ëìëë¤.
ìì²ì´
https://example.com/fooë¡ ë¦¬ëë ì ëììµëë¤. ì´ë ì¬ì ìì²ì´ íìí êµì°¨ ì¶ì² ìì²ì ëí´ íì©ëì§ ììµëë¤. ìì²ì ì¬ì ìì²ì´ íìí©ëë¤. ì´ë êµì°¨ ì¶ì² 리ëë í¸ë¥¼ íì©ëì§ ììµëë¤.
CORS íë¡í ì½ì ìë ê·¸ë¬í ëì(리ë¤ì´ë í¸)ì íìíì§ë§, ì´í ë ì´ì íìíì§ ìëë¡ ë³ê²½ëììµëë¤. ê·¸ë¬ë 모ë ë¸ë¼ì°ì ê° ë³ê²½ ì¬íì 구ííì§ë ìì기 ë문ì, ë°ë¼ì ìë íìíìë ëì(리ë¤ì´ë í¸)ì´ ì¬ì í ë³´ì ëë¤.
ë¸ë¼ì°ì ê° ëª ì¸ë¥¼ ë°ë¼ì¡ì ëê¹ì§ ë¤ì ì¤ íë ëë ë ë¤ ìííì¬ ì´ ì íì í´ê²°í ì ììµëë¤.
- ì¬ì ìì²ì í¼íê±°ë 리ëë ì ì í¼í기 ìí´(í¹ì ë ë¤) ìë² ì¸¡ ëìì ë³ê²½
- ì¬ì ìì²ì ë°ììí¤ì§ ìë ë¨ì ìì²ì¼ë¡ ë³ê²½
ì ë°©ë²ì´ ê°ë¥íì§ ìì ê²½ì° ë¤ë¥¸ ë°©ë²ë ììµëë¤.
- ì¤ì ì¬ì ìì²ì´ ëë¬í URL ì íë³í기 ìí´ Fetch API ì
Response.urlëëXMLHttpRequest.responseURLì ì¬ì©í´ ë¨ì ìì²ì ë§ëëë¤. - 첫 ë²ì§¸ ë¨ê³ìì
Response.urlí¹ìXMLHttpRequest.responseURLë¡ë¶í° ì»ì URLì ì¬ì©íì¬ ë ë¤ë¥¸ ìì²(ì¤ì ìì²)ì ë§ëëë¤.
ê·¸ë¬ë Authorization í¤ëê° í¬í¨ëì´ ìì´ ì¬ì ìì²ì í¸ë¦¬ê±° í ìì²ì´ë¼ë©´ ì ë¨ê³ë¥¼ íµí´ ì´ ì íì ì°íí ì ììµëë¤. ê·¸ë¦¬ê³ ìì²ì´ ì´ë¤ì§ë ìë²ì ëí ì ì´ê° ìë¤ë©´ ì í ì°íí ì ììµëë¤.
ì격 ì¦ëª ì í¬í¨í ìì²
ì°¸ê³ : ë¤ë¥¸ ëë©ì¸ì¼ë¡ ì격 ì¦ëª ìì²ì í ë, ìëíí° ì¿ í¤ ì ì± ì´ ì¬ì í ì ì©ë©ëë¤. ì´ ì ì± ì ìë²ì í´ë¼ì´ì¸í¸ìì ì¤ëª ë 모ë ì¤ì ê³¼ ê´ê³ìì´ íì ì ì©ë©ëë¤.
fetch() í¹ì XMLHttpRequest ì CORS ì íµí´ ì ê³µë ê°ì¥ í¥ë¯¸ë¡ì´ 기ë¥ì HTTP ì¿ í¤ì HTTP ì¸ì¦ ì 보를 ì¸ìíë "ì격 ì¦ëª
ì´ í¬í¨ë" ìì²ì í ì ìë¤ë ê²ì
ëë¤. 기본ì ì¼ë¡ êµì°¨ ì¶ì² fetch() ëë XMLHttpRequest í¸ì¶ììë ë¸ë¼ì°ì ê° ì격 ì¦ëª
ì ì ì¡íì§ ììµëë¤.
fetch() ìì²ì ì격 ì¦ëª
ì í¬í¨íë ¤ë©´, credentials ìµì
ì "include" ë¡ ì¤ì íììì¤.
XMLHttpRequest ìì²ì ì격 ì¦ëª
ì í¬í¨íë ¤ë©´, XMLHttpRequest.withCredentials ìì±ì true ë¡ ì¤ì íììì¤.
ì´ ìììì https://foo.example ìì ë¡ëë ì½í
ì¸ ë https://bar.other ì 리ìì¤ì ì¿ í¤ê° í¬í¨ë GET ë©ìë ë¨ì ìì²ì ë³´ë
ëë¤. foo.example ì ì½í
ì¸ ë ë¤ìê³¼ ê°ì JavaScript ì½ë를 í¬í¨í ì ììµëë¤.
const url = "https://bar.other/resources/credentialed-content/";
const request = new Request(url, { credentials: "include" });
const fetchPromise = fetch(request);
fetchPromise.then((response) => console.log(response));
ì´ ì½ëë Request ê°ì²´ë¥¼ ìì±íê³ , ìì±ììì credentials ìµì
ì "include" ë¡ ì¤ì í ë¤ì ì´ ìì²ì fetch() ì ì ë¬í©ëë¤. ì´ë GET ë©ìë ë¨ì ìì²ì´ê¸° ë문ì ì¬ì ìì²ì´ ìíëì§ ìì§ë§, ë¸ë¼ì°ì ë Access-Control-Allow-Credentials: true í¤ëê° ìë ìëµì ê±°ë¶íê³ , í¸ì¶í ì¹ ì½í
ì¸ ì ìëµì ì ê³µíì§ ììµëë¤.
ë¤ìì í´ë¼ì´ì¸í¸ì ìë² ê°ì ìí êµíì ëë¤.
GET /resources/credentialed-content/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Referer: https://foo.example/examples/credential.html
Origin: https://foo.example
Cookie: pageAccess=2
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
[text/plain payload]
ë¹ë¡ ìì²ì Cookie í¤ëê° https://bar.other ì ìí ì¿ í¤ë¥¼ í¬í¨íê³ ìì§ë§, ì´ ììì ì¤ëª
í ê²ì²ë¼ bar.other ê° Access-Control-Allow-Credentials í¤ëì true ê°ì í¬í¨íì¬ ìëµíì§ ìì¼ë©´, ìëµì 무ìëê³ ì¹ ì½í
ì¸ ì ì ê³µëì§ ììµëë¤.
ì¬ì ìì²ê³¼ ì격 ì¦ëª
CORS ì¬ì ìì²ìë ì격 ì¦ëª
ì´ ì ëë¡ í¬í¨ëì§ ììì¼ í©ëë¤. ì¬ì ìì²ì ëí ìëµì ì¤ì ìì²ì´ ì격 ì¦ëª
ê³¼ í¨ê» ìíë ì ììì ëíë´ê¸° ìí´ Access-Control-Allow-Credentials: true 를 ëª
ìí´ì¼ í©ëë¤.
ì°¸ê³ : ì¼ë¶ 기ì ì¸ì¦ ìë¹ì¤ë ì¬ì ìì²í ë TLS í´ë¼ì´ì¸í¸ ì¸ì¦ì를 ë³´ë´ë ê²ì ìì²í©ëë¤. ì´ë Fetch ì¬ìì ì´ê¸ëë ëìì ëë¤.
íì´ì´íì¤(Firefox)87 ë network.cors_preflight.allow_client_cert ì true ì¼ë¡ ì¤ì íì¬ ì´ ë¹íì¤ ëìì íì±ííë ê²ì íì©í©ëë¤.(Firefox bug 1511151) íì¬ Chromium ê¸°ë° ë¸ë¼ì°ì ë CORS ì¬ì ìì²ìì íì TLS í´ë¼ì´ì¸í¸ ì¸ì¦ì를 ì ì¡í©ëë¤ (Chrome bug 775438).
ì격 ì¦ëª ì´ í¬í¨ë ìì²ê³¼ ìì¼ëì¹´ë
ì격 ì¦ëª ì´ í¬í¨ë ìì²ì ìëµíë ê²½ì°
-
ìë²ë
Access-Control-Allow-Originìëµ í¤ë ê°ì¼ë¡ "*" ìì¼ëì¹´ë를 ì§ì í´ìë ì ëë©°, ëì ëª ìì ì¸ ì¶ì²ë¥¼ ì§ì í´ì¼ í©ëë¤. ì를 ë¤ì´Access-Control-Allow-Origin: https://example.com. -
ìë²ë
Access-Control-Allow-Headersìëµ í¤ë ê°ì¼ë¡ "*" ìì¼ëì¹´ë를 ì§ì í´ìë ì ëë©°, ëì ëª ìì ì¸ í¤ë ì´ë¦ 목ë¡ì ì§ì í´ì¼ í©ëë¤. ì를 ë¤ì´Access-Control-Allow-Headers: X-PINGOTHER, Content-Type. -
ìë²ë
Access-Control-Allow-Methodsìëµ í¤ë ê°ì¼ë¡ "*" ìì¼ëì¹´ë를 ì§ì í´ìë ì ëë©°, ëì ëª ìì ì¸ ë©ìë ì´ë¦ 목ë¡ì ì§ì í´ì¼ í©ëë¤. ì를 ë¤ì´Access-Control-Allow-Methods: POST, GET. -
ìë²ë
Access-Control-Expose-Headersìëµ í¤ë ê°ì¼ë¡ "*" ìì¼ëì¹´ë를 ì§ì í´ìë ì ëë©°, ëì ëª ìì ì¸ í¤ë ì´ë¦ 목ë¡ì ì§ì í´ì¼ í©ëë¤. ì를 ë¤ì´Access-Control-Expose-Headers: Content-Encoding, Kuma-Revision.
ìì²ì ì격 ì¦ëª
(ê°ì¥ ì¼ë°ì ì¼ë¡ë Cookie í¤ë)ì´ í¬í¨ëê³ ìëµì Access-Control-Allow-Origin: * í¤ë(ì¦, ìì¼ëì¹´ë)ê° í¬í¨ëì´ ìì¼ë©´, ë¸ë¼ì°ì ë ìëµì ëí ì ê·¼ì ì°¨ë¨íê³ ê°ë°ì ë구 ì½ìì CORS ì¤ë¥ë¥¼ ë³´ê³ í©ëë¤.
ê·¸ë¬ë ìì²ì ì격 ì¦ëª
(ì를 ë¤ì´ Cookie í¤ë)ì´ í¬í¨ëê³ ìëµì ìì¼ëì¹´ë ëì ì¤ì ì¶ì²(ì를 ë¤ì´ Access-Control-Allow-Origin: https://example.com)ê° í¬í¨ëì´ ìì¼ë©´, ë¸ë¼ì°ì ë ì§ì ë ì¶ì²ìì ìëµì ì ê·¼í ì ìëë¡ íì©í©ëë¤.
ëí ìëµì Access-Control-Allow-Origin í¤ë ê°ì ì¤ì ì¶ì²ê° ìë "*" ìì¼ëì¹´ëì¸ ê²½ì° ìëµì Set-Cookie í¤ëë ì¿ í¤ë¥¼ ì¤ì íì§ ììµëë¤.
ìë íí° ì¿ í¤
CORS ìëµì ì¤ì ë ì¿ í¤ë ì¼ë°ì ì¸ ìë íí°(third-party) ì¿ í¤ ì ì±
ì ì ì©ì ë°ìµëë¤. ìì ììì, íì´ì§ë foo.example ìì ë¡ëëì§ë§, ìëµì Cookie í¤ëë bar.other ìì ì ì¡ëë¯ë¡ ì¬ì©ìì ë¸ë¼ì°ì ê° ëª¨ë ìë-íí° ì¿ í¤ë¥¼ ê±°ë¶íëë¡ ì¤ì ë ê²½ì° í´ë¹ ì¿ í¤ë ì ì¥ëì§ ììµëë¤.
ìì²ì ì¿ í¤ë ì¼ë°ì ì¸ ìë-íí° ì¿ í¤ ì ì± ì ë°ë¼ ìµì ë ì ììµëë¤. ë°ë¼ì ê°ì ë ì¿ í¤ ì ì± ì ì´ ì¥ìì ì¤ëª ë 기ë¥ì 무í¨í í ì ìì¼ë©°, ì격 ì¦ëª ì´ í¬í¨ë ìì²ì ì í ìíí ì ìê² ë§ë¤ ì ììµëë¤.
SameSite ìì±ì ëí ì¿ í¤ ì ì± ì´ ì ì©ë©ëë¤.
HTTP ìëµ í¤ë
ì´ ì¹ì ììë êµì°¨ ì¶ì² 리ìì¤ ê³µì ëª ì¸ì ì ìë ëë¡ ìë²ê° ì ê·¼ ì ì´ ìì²ì ìí´ ë³´ë´ë HTTP ìëµ í¤ëê° ëì´ëì´ ììµëë¤. ì´ì ì¹ì ììë ì´ë¬í ë´ì©ì´ ì¤ì ë¡ ì´ë»ê² ìëíëì§ì ëí ê°ì를 ì ê³µí©ëë¤.
Access-Control-Allow-Origin
ë°íë 리ìì¤ìë ë¤ì 구문과 í¨ê» íëì Access-Control-Allow-Origin í¤ëê° ìì ì ììµëë¤.
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin ì ë¨ì¼ ì¶ì²ë¥¼ ì§ì íì¬ ë¸ë¼ì°ì ê° í´ë¹ ì¶ì²ê° 리ìì¤ì ì ê·¼íëë¡ íì©í©ëë¤. ëë ì격 ì¦ëª
ì´ ìë ìì²ì ê²½ì° "*" ìì¼ëì¹´ëë ë¸ë¼ì°ì ì originì ìê´ìì´ ëª¨ë 리ìì¤ì ì ê·¼íëë¡ íì©í©ëë¤.
ì를 ë¤ì´ https://mozilla.org ì ì½ëê° ë¦¬ìì¤ì ì ê·¼í ì ìëë¡ íë ¤ë©´ ë¤ìê³¼ ê°ì´ ì§ì í ì ììµëë¤.
Access-Control-Allow-Origin: https://mozilla.org
Vary: Origin
ìë²ê° "*" ìì¼ëì¹´ë ëì ì íëì ì¶ì²ë¥¼ ì§ì íë ê²½ì°(ì´ ì¶ì²ë íê°ë ì¶ì² 리ì¤í¸ì ì¼ë¶ë¡ ìì² ì¶ì²ì ë°ë¼ ëì ì¼ë¡ ë³ê²½í ì ììµëë¤.), ìë²ë ìëµì´ Origin ìì² í¤ëì ë°ë¼ ë¤ë¥´ë¤ë ê²ì í´ë¼ì´ì¸í¸ì ìë ¤ì£¼ê¸° ìí´ Vary ìëµ í¤ëì Origin ì í¬í¨í´ì¼ í©ëë¤.
Access-Control-Expose-Headers
Access-Control-Expose-Headers í¤ëë JavaScript(ì를 ë¤ì´ Response.headers)ê° ë¸ë¼ì°ì ìì ì ê·¼í ì ìë íì©ë í¤ë 목ë¡ì ì§ì ë í¤ë를 ì¶ê°í©ëë¤.
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
ì를 ë¤ë©´ ë¤ìê³¼ ê°ìµëë¤.
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
ì ìëµì ìí´ X-My-Custom-Header ì X-Another-Custom-Header í¤ëê° ë¸ë¼ì°ì ì ë
¸ì¶ë©ëë¤.
Access-Control-Max-Age
Access-Control-Max-Age í¤ëë ì¬ì ìì² ê²°ê³¼ë¥¼ ìºìí ì ìë ìê°ì ëíë
ëë¤. ì¬ì ìì² ìì ë ì를 참조íì¸ì.
Access-Control-Max-Age: <delta-seconds>
delta-seconds íë¼ë¯¸í°ë 결과를 ìºìí ì ìë ìê°(ì´)ì ëíë
ëë¤.
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials í¤ëë credentialsê° ì°¸ì¼ ë ìì²ì ëí ìëµì íìí ì ìëì§ ì¬ë¶ë¥¼ ëíë
ëë¤. ì¬ì ìì²ì ëí ìëµì ì¼ë¶ë¡ ì¬ì©ë ë, ì´ í¤ëë ì¤ì ìì²ì´ ì격 ì¦ëª
ê³¼ í¨ê» ìíë ì ìëì§ ì¬ë¶ë¥¼ ëíë
ëë¤. ë¨, GET ë©ìë ë¨ì ìì²ì ì¬ì ìì²ì´ ìíëì§ ìì¼ë¯ë¡, ì격 ì¦ëª
ê³¼ í¨ê» 리ìì¤ì ëí ìì²ì´ ì´ë£¨ì´ì§ ê²½ì° ì´ í¤ëê° ë¦¬ìì¤ì í¨ê» ë°íëì§ ìì¼ë©´ ë¸ë¼ì°ì ë ìëµì 무ìíê³ ì¹ ì½í
ì¸ ì ë°ííì§ ììµëë¤.
Access-Control-Allow-Credentials: true
ì격 ì¦ëª ì´ í¬í¨ë ìì²ì ììì ë ¼ìíììµëë¤.
Access-Control-Allow-Methods
Access-Control-Allow-Methods í¤ëë 리ìì¤ì ì ê·¼í ë íì©ëë ë©ìë를 ì§ì í©ëë¤. ì´ í¤ëë ì¬ì ìì²ì ëí ìëµì¼ë¡ ì¬ì©ë©ëë¤. ì¬ì ìì²ì´ ë°ìíë ì¡°ê±´ì ììì ë
¼ìíììµëë¤.
Access-Control-Allow-Methods: <method>[, <method>]*
ìì ì¬ì ìì²ì ìê° ì ê³µëì´ ìì¼ë©°, ì´ ìììë ì´ í¤ë를 ë¸ë¼ì°ì ì ì ì¡íë ìê° í¬í¨ëì´ ììµëë¤.
Access-Control-Allow-Headers
Access-Control-Allow-Headers í¤ëë ì¬ì ìì²ì ëí ìëµì¼ë¡ ì¬ì©ëë©°, ì¤ì ìì²ì í ë ì¬ì©í ì ìë HTTP í¤ë를 ëíë
ëë¤. ì´ í¤ëë ë¸ë¼ì°ì ì Access-Control-Request-Headers í¤ëì ëí ìë² ì¸¡ì ìëµì
ëë¤.
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
HTTP ìì² í¤ë
ì´ ì¹ì ììë í´ë¼ì´ì¸í¸ê° êµì°¨ ì¶ì² ê³µì 기ë¥ì ì¬ì©í기 ìí´ HTTP ìì²ì ë°íí ë ì¬ì©í ì ìë í¤ëë¤ì ëì´í©ëë¤. ì´ë¬í í¤ëë ìë²ë¥¼ í¸ì¶í ë ê°ë°ì를 ìí´ ì¤ì ë©ëë¤. êµì°¨ ì¶ì² ìì²ì ë§ëë ê°ë°ìë ì´ë¬í êµì°¨ ì¶ì² ê³µì ìì² í¤ë를 íë¡ê·¸ëë°ì ì¼ë¡ ì¤ì í íìê° ììµëë¤.
Origin
Origin í¤ëë êµì°¨ ì¶ì² ì ê·¼ ìì² ëë ì¬ì ìì² ì¶ì²ë¥¼ ëíë
ëë¤.
Origin: <origin>
origin ê°ì ìì²ì´ ììë ìë²ë¥¼ ëíë´ë URI ì ëë¤. ê²½ë¡ ì ë³´ë í¬í¨íì§ ìê³ , ì¤ì§ ìë² ì´ë¦ë§ í¬í¨í©ëë¤.
ì°¸ê³ :
origin ê°ì null ëë URI ê° ì¬ ì ììµëë¤.
ì ê·¼ ì ì´ ìì²ìë íì Origin í¤ëê° ì ì¡ë©ëë¤.
Access-Control-Request-Method
Access-Control-Request-Method í¤ëë ì¤ì ìì²ìì ì´ë¤ HTTP ë©ìë를 ì¬ì©í ì§ ìë²ìê² ìë ¤ì£¼ê¸° ìí´ ì¬ì ìì²í ë ì¬ì©ë©ëë¤.
Access-Control-Request-Method: <method>
ì´ ì¬ì©ë²ì ìì ë ììì ì°¾ì ì ììµëë¤.
Access-Control-Request-Headers
Access-Control-Request-Headers í¤ëë ì¬ì ìì²ì ë°íí ë ì¬ì©ëë©°, ì¤ì ìì²ìì ì¬ì©í HTTP í¤ë를 ìë²ì ì리기 ìí´ ì¬ì©ë©ëë¤(ì를 ë¤ì´ headers ìµì
ì íµí´ ì ë¬). ì´ ë¸ë¼ì°ì 측 í¤ëë Access-Control-Allow-Headers ë¼ë ìë² ì¸¡ í¤ëë¡ ìëµ ë°ê² ë©ëë¤.
Access-Control-Request-Headers: <field-name>[,<field-name>]*
ì´ ì¬ì©ë²ì ìì ë ììì ì°¾ì ì ììµëë¤.
ëª ì¸ì
| Specification |
|---|
| Fetch > # http-access-control-allow-origin > |
ë¸ë¼ì°ì í¸íì±
ê°ì´ 보기
- CORS errors
- CORS íì±í: ë´ ìë²ì CORS ì§ìì ì¶ê°íê³ ì¶ë¤
XMLHttpRequest- Fetch API
- CORS ì¼ê¹ì? - an interactive CORS explainer & generator
- 모ë (íë) ë¸ë¼ì°ì ìì CORS ì¬ì©í기
- CORS ìì´ Chrome ë¸ë¼ì°ì 를 ì¤ííë ë°©ë²
- ì¼ë°ì ì¸ ë¬¸ì 를 ë¤ë£¨ê¸° ìí ë°©ë²ì ëí ì¤í ì¤ë²íë¡ì° ëµë³:
- How to avoid the CORS preflight
- How to use a CORS proxy to get around "No Access-Control-Allow-Origin header"
- How to fix "Access-Control-Allow-Origin header must not be the wildcard"