è·¨æºèµæºå ±äº«ï¼CORSï¼
åºçº¿
广æ³å¯ç¨
èª 2015å¹´7æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
è·¨æºèµæºå ±äº«ï¼CORSï¼æéä¿å°è¯ä¸ºè·¨åèµæºå ±äº«ï¼æ¯ä¸ç§åºäº HTTP å¤´çæºå¶ï¼è¯¥æºå¶éè¿å 许æå¡å¨æ 示é¤äºå®èªå·±ä»¥å¤çå ¶ä»æºï¼åãåè®®æç«¯å£ï¼ï¼ä½¿å¾æµè§å¨å 许è¿äºæºè®¿é®å è½½èªå·±çèµæºãè·¨æºèµæºå ±äº«è¿éè¿ä¸ç§æºå¶æ¥æ£æ¥æå¡å¨æ¯å¦ä¼å 许è¦åéççå®è¯·æ±ï¼è¯¥æºå¶éè¿æµè§å¨åèµ·ä¸ä¸ªå°æå¡å¨æç®¡çè·¨æºèµæºçâ颿£â请æ±ãå¨é¢æ£ä¸ï¼æµè§å¨åéç头䏿 示æ HTTP æ¹æ³åçå®è¯·æ±ä¸ä¼ç¨å°ç头ã
è·¨æº HTTP 请æ±çä¸ä¸ªä¾åï¼è¿è¡å¨ https://domain-a.com ç JavaScript 代ç ä½¿ç¨ XMLHttpRequest æ¥åèµ·ä¸ä¸ªå° https://domain-b.com/data.json ç请æ±ã
åºäºå®å
¨æ§ï¼æµè§å¨éå¶èæ¬å
åèµ·çè·¨æº HTTP 请æ±ãä¾å¦ï¼XMLHttpRequest å Fetch API éµå¾ªåæºçç¥ãè¿æå³ç使ç¨è¿äº API ç Web åºç¨ç¨åºåªè½ä»å è½½åºç¨ç¨åºçåä¸ä¸ªåè¯·æ± HTTP èµæºï¼é¤éååºæ¥æå
å«äºæ£ç¡® CORS ååºå¤´ã
CORS æºå¶å
许 Web åºç¨æå¡å¨è¿è¡è·¨æºè®¿é®æ§å¶ï¼ä»èä½¿è·¨æºæ°æ®ä¼ è¾å¾ä»¥å®å
¨è¿è¡ãç°ä»£æµè§å¨æ¯æå¨ API 容å¨ä¸ï¼ä¾å¦ XMLHttpRequest æ Fetchï¼ä½¿ç¨ CORSï¼ä»¥éä½è·¨æº HTTP è¯·æ±æå¸¦æ¥çé£é©ã
ä»ä¹æ åµä¸éè¦ CORSï¼
è¿ä»½è·¨æºå ±äº«æ åå 许å¨ä¸ååºæ¯ä¸ä½¿ç¨è·¨ç«ç¹ HTTP 请æ±ï¼
- åææå°çç±
XMLHttpRequestæ Fetch API åèµ·çè·¨æº HTTP 请æ±ã - Web åä½ï¼CSS ä¸éè¿
@font-face使ç¨è·¨æºåä½èµæºï¼ï¼å æ¤ï¼ç½ç«å°±å¯ä»¥åå¸ TrueType åä½èµæºï¼å¹¶åªå 许已ææç½ç«è¿è¡è·¨ç«è°ç¨ã - WebGL è´´å¾ã
- 使ç¨
drawImage()å°å¾çæè§é¢ç»é¢ç»å¶å° canvasã - æ¥èªå¾åç CSS å¾å½¢ã
æ¬ææ¦è¿°äºè·¨æºèµæºå ±äº«æºå¶åå ¶ææ¶åç HTTP æ 头ã
åè½æ¦è¿°
è·¨æºèµæºå
±äº«æ åæ°å¢äºä¸ç» HTTP æ 头忮µï¼å
许æå¡å¨å£°æåªäºæºç«éè¿æµè§å¨ææé访é®åªäºèµæºãå¦å¤ï¼è§èè¦æ±ï¼å¯¹é£äºå¯è½å¯¹æå¡å¨æ°æ®äº§çå¯ä½ç¨ç HTTP è¯·æ±æ¹æ³ï¼ç¹å«æ¯ GET 以å¤ç HTTP 请æ±ï¼æè
æé
æäº MIME ç±»åç POST 请æ±ï¼ï¼æµè§å¨å¿
é¡»é¦å
ä½¿ç¨ OPTIONS æ¹æ³åèµ·ä¸ä¸ªé¢æ£è¯·æ±ï¼preflight requestï¼ï¼ä»èè·ç¥æå¡ç«¯æ¯å¦å
许该跨æºè¯·æ±ãæå¡å¨ç¡®è®¤å
许ä¹åï¼æåèµ·å®é
ç HTTP 请æ±ãå¨é¢æ£è¯·æ±çè¿åä¸ï¼æå¡å¨ç«¯ä¹å¯ä»¥éç¥å®¢æ·ç«¯ï¼æ¯å¦éè¦æºå¸¦èº«ä»½åè¯ï¼ä¾å¦ Cookie å HTTP 认è¯ç¸å
³æ°æ®ï¼ã
CORS 请æ±å¤±è´¥ä¼äº§çé误ï¼ä½æ¯ä¸ºäºå®å ¨ï¼å¨ JavaScript 代ç å±é¢æ æ³è·ç¥å°åºå ·ä½æ¯åªéåºäºé®é¢ãä½ åªè½æ¥çæµè§å¨çæ§å¶å°ä»¥å¾ç¥å ·ä½æ¯åªéåºç°äºé误ã
æ¥ä¸æ¥çå 容å°è®¨è®ºç¸å ³åºæ¯ï¼å¹¶åæè¯¥æºå¶ææ¶åç HTTP æ 头忮µã
è¥å¹²è®¿é®æ§å¶åºæ¯
è¿éï¼æä»¬ä½¿ç¨ä¸ä¸ªåºæ¯æ¥è§£éè·¨æºèµæºå
±äº«æºå¶çå·¥ä½åçãè¿äºä¾åé½ä½¿ç¨å¨ä»»æææ¯æçæµè§å¨ä¸é½å¯ä»¥ååºè·¨å请æ±ç XMLHttpRequest 对象ã
ç®å请æ±
æäºè¯·æ±ä¸ä¼è§¦å CORS 颿£è¯·æ±ãå¨åºå¼ç CORS è§èä¸ç§°è¿æ ·ç请æ±ä¸ºç®å请æ±ï¼ä½æ¯ç®åç Fetch è§èï¼CORS çç°è¡å®ä¹è§èï¼ä¸ä¸å使ç¨è¿ä¸ªè¯è¯ã
å
¶å¨æºæ¯ï¼HTML 4.0 ä¸ç <form> å
ç´ ï¼æ©äºè·¨ç« XMLHttpRequest å fetchï¼å¯ä»¥å任使¥æºæäº¤ç®å请æ±ï¼æä»¥ä»»ä½ç¼åæå¡å¨ç人ä¸å®å·²ç»å¨ä¿æ¤è·¨ç«è¯·æ±ä¼ªé æ»å»ï¼CSRFï¼ãå¨è¿ä¸ªå设ä¸ï¼æå¡å¨ä¸å¿
éæ©å å
¥ï¼éè¿ååºé¢æ£è¯·æ±ï¼æ¥æ¥æ¶ä»»ä½çèµ·æ¥å表åæäº¤ç请æ±ï¼å 为 CSRF çå¨è并䏿¯è¡¨åæäº¤çå¨èå·®ãç¶èï¼æå¡å¨ä»ç¶å¿
é¡»æä¾ Access-Control-Allow-Origin çéæ©ï¼ä»¥ä¾¿ä¸èæ¬å
±äº«ååºã
è¥è¯·æ±æ»¡è¶³ææä¸è¿°æ¡ä»¶ï¼å该请æ±å¯è§ä¸ºç®å请æ±ï¼
-
使ç¨ä¸åæ¹æ³ä¹ä¸ï¼
-
é¤äºè¢«ç¨æ·ä»£çèªå¨è®¾ç½®çæ 头忮µï¼ä¾å¦
ConnectionãUser-Agentæå ¶ä»å¨ Fetch è§èä¸å®ä¹ä¸ºç¦ç¨æ 头åç§°çæ å¤´ï¼ï¼å 许人为设置çåæ®µä¸º Fetch è§èå®ä¹ç对 CORS å®å ¨çæ 头忮µéåã该éå为ï¼AcceptAccept-LanguageContent-LanguageContent-Typeï¼éè¦æ³¨æé¢å¤çéå¶ï¼Rangeï¼åªå 许ç®åçèå´æ å¤´å¼ å¦bytes=256-æbytes=127-255ï¼
-
Content-Typeæ 头ææå®çåªä½ç±»åçå¼ä» éäºä¸åä¸è ä¹ä¸ï¼text/plainmultipart/form-dataapplication/x-www-form-urlencoded
-
å¦æè¯·æ±æ¯ä½¿ç¨
XMLHttpRequest对象ååºçï¼å¨è¿åçXMLHttpRequest.uploadå¯¹è±¡å±æ§ä¸æ²¡ææ³¨åä»»ä½äºä»¶çå¬å¨ï¼ä¹å°±æ¯è¯´ï¼ç»å®ä¸ä¸ªXMLHttpRequestå®ä¾xhrï¼æ²¡æè°ç¨xhr.upload.addEventListener()ï¼ä»¥çå¬è¯¥ä¸ä¼ 请æ±ã -
请æ±ä¸æ²¡æä½¿ç¨
ReadableStream对象ã
夿³¨ï¼WebKit Nightly å Safari Technology Preview 为 AcceptãAccept-Language å Content-Language æ 头忮µç弿·»å äºé¢å¤çéå¶ã妿è¿äºæ 头忮µç弿¯âéæ åâçï¼WebKit/Safari å°±ä¸ä¼å°è¿äºè¯·æ±è§ä¸ºâç®å请æ±âãWebKit/Safari 并没æå¨ææ¡£ä¸ååºåªäºå¼æ¯âéæ åâçï¼ä¸è¿æä»¬å¯ä»¥å¨è¿éæ¾å°ç¸å
³è®¨è®ºï¼
- 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
å ¶ä»æµè§å¨å¹¶ä¸æ¯æè¿äºé¢å¤çéå¶ï¼å 为å®ä»¬ä¸å±äºè§èçä¸é¨åã
æ¯å¦è¯´ï¼åå¦ç«ç¹ https://foo.example çç½é¡µåºç¨æ³è¦è®¿é® https://bar.other çèµæºã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 表æè¯¥è¯·æ±æ¥æºäº http://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 çå¼ï¼èä¸è½ä½¿ç¨éé
符â*âã
颿£è¯·æ±
ä¸ç®å请æ±ä¸åï¼âé颿£ç请æ±âè¦æ±å¿
é¡»é¦å
ä½¿ç¨ 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 çä¸é¨åï¼ä½éå¸¸å¯¹äº web åºç¨å¾æç¨å¤ãå¦å¤ï¼è¯¥è¯·æ±ç Content-Type 为 application/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: X-PINGOTHER, Content-Type
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
ä»ä¸é¢çæ¥æä¸ï¼æä»¬çå°ï¼ç¬¬ 1 - 10 è¡ä½¿ç¨ OPTIONS æ¹æ³åéäºé¢æ£è¯·æ±ï¼æµè§å¨æ ¹æ®ä¸é¢ç JavaScript 代ç çææä½¿ç¨ç请æ±åæ°æ¥å³å®æ¯å¦éè¦åéï¼è¿æ ·æå¡å¨å°±å¯ä»¥ååºæ¯å¦å¯ä»¥æ¥åç¨å®é
ç请æ±åæ°æ¥åé请æ±ãOPTIONS æ¯ HTTP/1.1 åè®®ä¸å®ä¹çæ¹æ³ï¼ç¨äºä»æå¡å¨è·åæ´å¤ä¿¡æ¯ï¼æ¯å®å
¨çæ¹æ³ãè¯¥æ¹æ³ä¸ä¼å¯¹æå¡å¨èµæºäº§çå½±åãæ³¨æ OPTIONS 颿£è¯·æ±ä¸åæ¶æºå¸¦äºä¸é¢ä¸¤ä¸ªæ 头忮µï¼
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
æ 头忮µ Access-Control-Request-Method åç¥æå¡å¨ï¼å®é
请æ±å°ä½¿ç¨ POST æ¹æ³ãæ 头忮µ Access-Control-Request-Headers åç¥æå¡å¨ï¼å®é
请æ±å°æºå¸¦ä¸¤ä¸ªèªå®ä¹è¯·æ±æ 头忮µï¼X-PINGOTHER ä¸ Content-Typeãæå¡å¨æ®æ¤å³å®ï¼è¯¥å®é
è¯·æ±æ¯å¦è¢«å
许ã
第 12 - 21 è¡ä¸ºé¢æ£è¯·æ±çååºï¼è¡¨ææå¡å¨å°æ¥ååç»çå®é
è¯·æ±æ¹æ³ï¼POSTï¼å请æ±å¤´ï¼X-PINGOTHERï¼ãéç¹ç第 15 - 18 è¡ï¼
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 å°æ¶ã请注æï¼æµè§å¨èªèº«ç»´æ¤äºä¸ä¸ªæå¤§æææ¶é´ï¼å¦æè¯¥æ 头忮µçå¼è¶
è¿äºæå¤§æææ¶é´ï¼å°ä¸ä¼çæã
颿£è¯·æ±å®æä¹åï¼åéå®é 请æ±ï¼
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]
颿£è¯·æ±ä¸éå®å
并䏿¯æææµè§å¨é½æ¯æé¢æ£è¯·æ±çéå®åã妿ä¸ä¸ªé¢æ£è¯·æ±åçäºéå®åï¼ä¸é¨åæµè§å¨å°æ¥åé误ï¼
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight. Request requires preflight, which is disallowed to follow cross-origin redirects.
CORS æåè¦æ±æµè§å¨å ·æè¯¥è¡ä¸ºï¼ä¸è¿å¨åç»ç修订ä¸åºå¼äºè¿ä¸è¦æ±ãä½å¹¶éæææµè§å¨é½å®ç°äºè¿ä¸åæ´ï¼èä»ç¶è¡¨ç°åºæåè¦æ±çè¡ä¸ºã
卿µè§å¨çå®ç°è·ä¸è§èä¹åï¼æä¸¤ç§æ¹å¼è§é¿ä¸è¿°æ¥éè¡ä¸ºï¼
- 卿å¡ç«¯å»æå¯¹é¢æ£è¯·æ±çéå®åï¼
- å°å®é 请æ±åæä¸ä¸ªç®å请æ±ã
妿ä¸é¢ä¸¤ç§æ¹å¼é¾ä»¥åå°ï¼æä»¬ä»æå ¶ä»åæ³ï¼
- ååºä¸ä¸ªç®å请æ±ï¼ä½¿ç¨ Fetch API ä¸ç
Response.urlæXMLHttpRequest.responseURLï¼ä»¥å¤æçæ£ç颿£è¯·æ±ä¼è¿åä»ä¹å°åã - ååºå¦ä¸ä¸ªè¯·æ±ï¼çæ£ç请æ±ï¼ï¼ä½¿ç¨å¨ä¸ä¸æ¥éè¿
Response.urlæXMLHttpRequest.responseURLè·å¾ç URLã
ä¸è¿ï¼å¦æè¯·æ±æ¯ç±äºåå¨ Authorization åæ®µèå¼åäºé¢æ£è¯·æ±ï¼åè¿ä¸æ¹æ³å°æ æ³ä½¿ç¨ãè¿ç§æ
åµåªè½ç±æå¡ç«¯è¿è¡æ´æ¹ã
é带身份åè¯ç请æ±
夿³¨ï¼å½ååºè·¨æºè¯·æ±æ¶ï¼ç¬¬ä¸æ¹ cookie çç¥ä»å°éç¨ãæ 论å¦ä½æ¹åæ¬ç« èä¸æè¿°çæå¡å¨å客æ·ç«¯ç设置ï¼è¯¥çç¥é½ä¼å¼ºå¶æ§è¡ã
XMLHttpRequest æ Fetch ä¸ CORS çä¸ä¸ªæè¶£çç¹æ§æ¯ï¼å¯ä»¥åºäº HTTP cookies å HTTP 认è¯ä¿¡æ¯åé身份åè¯ãä¸è¬èè¨ï¼å¯¹äºè·¨æº XMLHttpRequest æ Fetch 请æ±ï¼æµè§å¨ä¸ä¼åé身份åè¯ä¿¡æ¯ã妿è¦åéåè¯ä¿¡æ¯ï¼éè¦è®¾ç½® XMLHttpRequest 对象çæä¸ªç¹æ®æ å¿ä½ï¼æå¨æé Request 对象æ¶è®¾ç½®ã
æ¬ä¾ä¸ï¼https://foo.example çæèæ¬å https://bar.other åèµ·ä¸ä¸ª GET 请æ±ï¼å¹¶è®¾ç½® Cookiesãå¨ 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 ä¸çå
容æå®ç cookieï¼ä½å¦æ bar.other 没æåæ¬ä¾ä¸æ¼ç¤ºç飿 ·ååºä¸ä¸ªå¼ä¸º true ç Access-Control-Allow-Credentialsï¼è¯¥ååºå°è¢«å¿½ç¥ï¼ç½ç»å
容尿 æ³ä½¿ç¨ã
颿£è¯·æ±ååæ®
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ï¼ï¼
è¿æ¯å 为请æ±çæ 头䏿ºå¸¦äº Cookie ä¿¡æ¯ï¼å¦æ Access-Control-Allow-Origin çå¼ä¸ºâ*âï¼è¯·æ±å°ä¼å¤±è´¥ãèå° Access-Control-Allow-Origin çå¼è®¾ç½®ä¸º https://example.comï¼å请æ±å°æåæ§è¡ã
å¦å¤ï¼ååºæ 头ä¸ä¹æºå¸¦äº Set-Cookie åæ®µï¼å°è¯å¯¹ Cookie è¿è¡ä¿®æ¹ã妿æä½å¤±è´¥ï¼å°ä¼æåºå¼å¸¸ã
ç¬¬ä¸æ¹ cookie
注æå¨ CORS ååºä¸è®¾ç½®ç cookie éç¨ä¸è¬æ§ç¬¬ä¸æ¹ cookie çç¥ãå¨ä¸é¢çä¾åä¸ï¼é¡µé¢æ¯å¨ foo.example å è½½ï¼ä½æ¯ç¬¬ 19 è¡ç cookie æ¯è¢« bar.other åéçï¼å¦æç¨æ·è®¾ç½®å
¶æµè§å¨æç»ææç¬¬ä¸æ¹ cookieï¼é£ä¹å°ä¸ä¼è¢«ä¿åã
请æ±ä¸ç cookieï¼ç¬¬ 10 è¡ï¼ä¹å¯è½å¨æ£å¸¸çç¬¬ä¸æ¹ cookie çç¥ä¸è¢«é»æ¢ãå æ¤ï¼å¼ºå¶æ§è¡ç cookie çç¥å¯è½ä¼ä½¿æ¬èæè¿°çå å®¹æ æï¼é»æ¢ä½ ååºä»»ä½æºå¸¦åæ®ç请æ±ï¼ã
Cookie çç¥å SameSite 屿§æ§å¶ã
HTTP ååºæ 头忮µ
æ¬èååºäºæå¡å¨ä¸ºè®¿é®æ§å¶è¯·æ±è¿åç HTTP ååºå¤´ï¼è¿æ¯ç±è·¨æºèµæºå ±äº«è§èå®ä¹çãä¸ä¸å°èä¸ï¼æä»¬å·²ç»çå°äºè¿äºæ 头忮µå¨å®é åºæ¯ä¸æ¯å¦ä½å·¥ä½çã
Access-Control-Allow-Origin
ååºæ 头ä¸å¯ä»¥æºå¸¦ä¸ä¸ª Access-Control-Allow-Origin åæ®µï¼å
¶è¯æ³å¦ä¸ï¼
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin åæ°æå®äºåä¸çæºï¼åè¯æµè§å¨å
许该æºè®¿é®èµæºãæè
ï¼å¯¹äºä¸éè¦æºå¸¦èº«ä»½åè¯ç请æ±ï¼æå¡å¨å¯ä»¥æå®è¯¥å段çå¼ä¸ºéé
符â*âï¼è¡¨ç¤ºå
许æ¥èªä»»ææºç请æ±ã
ä¾å¦ï¼ä¸ºäºå
许æ¥èª https://mozilla.org ç代ç 访é®èµæºï¼ä½ å¯ä»¥æå®ï¼
Access-Control-Allow-Origin: https://mozilla.org
Vary: Origin
妿æå¡ç«¯æå®äºå
·ä½çå个æºï¼ä½ä¸ºå
许å表çä¸é¨åï¼å¯è½ä¼æ ¹æ®è¯·æ±çæ¥æºè卿æ¹åï¼èééé
符ï¼*ï¼ï¼é£ä¹ååºæ 头ä¸ç Vary åæ®µçå¼å¿
é¡»å
å« Originãè¿å°åè¯å®¢æ·ç«¯ï¼æå¡å¨å¯¹ä¸åç Origin è¿åä¸åçå
容ã
Access-Control-Expose-Headers
è¯è
注ï¼å¨è·¨æºè®¿é®æ¶ï¼XMLHttpRequest 对象ç getResponseHeader() æ¹æ³åªè½æ¿å°ä¸äºæåºæ¬çååºå¤´ï¼Cache-ControlãContent-LanguageãContent-TypeãExpiresãLast-ModifiedãPragmaï¼å¦æè¦è®¿é®å
¶ä»å¤´ï¼åéè¦æå¡å¨è®¾ç½®æ¬ååºå¤´ã
Access-Control-Expose-Headers 头尿宿 头æ¾å
¥å
许å表ä¸ï¼ä¾æµè§å¨ç JavaScript 代ç ï¼å¦ getResponseHeader()ï¼è·åã
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
ä¾å¦ï¼
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
è¿æ ·æµè§å¨å°±è½å¤éè¿ getResponseHeader è®¿é® X-My-Custom-Header å X-Another-Custom-Header ååºå¤´äºã
Access-Control-Max-Age
Access-Control-Max-Age 头æå®äº preflight 请æ±çç»æè½å¤è¢«ç¼åå¤ä¹
ï¼è¯·åèæ¬æå¨å颿å°ç preflight ä¾åã
Access-Control-Max-Age: <delta-seconds>
delta-seconds åæ°è¡¨ç¤º preflight 颿£è¯·æ±çç»æå¨å¤å°ç§å
ææã
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials 头æå®äºå½æµè§å¨ç credentials 设置为 true æ¶æ¯å¦å
许æµè§å¨è¯»å response çå
容ãå½ç¨å¨å¯¹ preflight 颿£æµè¯·æ±çååºä¸æ¶ï¼å®æå®äºå®é
çè¯·æ±æ¯å¦å¯ä»¥ä½¿ç¨ credentialsã请注æï¼ç®å GET 请æ±ä¸ä¼è¢«é¢æ£ï¼å¦æå¯¹æ¤ç±»è¯·æ±çååºä¸ä¸å
å«è¯¥å段ï¼è¿ä¸ªååºå°è¢«å¿½ç¥æï¼å¹¶ä¸æµè§å¨ä¹ä¸ä¼å°ç¸åºå
容è¿åç»ç½é¡µã
Access-Control-Allow-Credentials: true
䏿已ç»è®¨è®ºäºé带身份åè¯ç请æ±ã
Access-Control-Allow-Methods
Access-Control-Allow-Methods æ 头忮µæå®äºè®¿é®èµæºæ¶å
许使ç¨çè¯·æ±æ¹æ³ï¼ç¨äºé¢æ£è¯·æ±çååºãå
¶ææäºå®é
è¯·æ±æå
许使ç¨ç HTTP æ¹æ³ã
Access-Control-Allow-Methods: <method>[, <method>]*
æå ³é¢æ£è¯·æ±ç示ä¾å·²å¨ä¸æ¹ç»åºï¼å å«äºå°æ¤è¯·æ±å¤´åéè³æµè§å¨ç示ä¾ã
Access-Control-Allow-Headers
Access-Control-Allow-Headers æ 头忮µç¨äºé¢æ£è¯·æ±çååºãå
¶ææäºå®é
请æ±ä¸å
许æºå¸¦çæ 头忮µãè¿ä¸ªæ å¤´æ¯æå¡å¨ç«¯å¯¹æµè§å¨ç«¯ Access-Control-Request-Headers æ 头çååºã
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
HTTP è¯·æ±æ 头忮µ
æ¬èååºäºå¯ç¨äºåèµ·è·¨æºè¯·æ±çæ 头忮µã请注æï¼è¿äºæ 头忮µæ é¡»æå¨è®¾ç½®ãå½å¼åè
ä½¿ç¨ XMLHttpRequest 对象åèµ·è·¨æºè¯·æ±æ¶ï¼å®ä»¬å·²ç»è¢«è®¾ç½®å°±ç»ªã
Origin
Origin æ 头忮µè¡¨æé¢æ£è¯·æ±æå®é
è·¨æºè¯·æ±çæºç«ã
Origin: <origin>
origin åæ°çå¼ä¸ºæºç« URLãå®ä¸å å«ä»»ä½è·¯å¾ä¿¡æ¯ï¼åªæ¯æå¡å¨åç§°ã
夿³¨ï¼origin çå¼å¯ä»¥ä¸º nullã
注æï¼å¨ææè®¿é®æ§å¶è¯·æ±ä¸ï¼Origin æ 头忮µæ»æ¯è¢«åéã
Access-Control-Request-Method
Access-Control-Request-Method æ 头忮µç¨äºé¢æ£è¯·æ±ãå
¶ä½ç¨æ¯ï¼å°å®é
è¯·æ±æä½¿ç¨ç HTTP æ¹æ³åè¯æå¡å¨ã
Access-Control-Request-Method: <method>
ç¸å ³ç¤ºä¾è§è¿éã
Access-Control-Request-Headers
Access-Control-Request-Headers æ 头忮µç¨äºé¢æ£è¯·æ±ãå
¶ä½ç¨æ¯ï¼å°å®é
è¯·æ±ææºå¸¦çæ 头忮µï¼éè¿ setRequestHeader() ç设置çï¼åè¯æå¡å¨ãè¿ä¸ªæµè§å¨ç«¯æ 头å°ç±äºè¡¥çæå¡å¨ç«¯æ 头 Access-Control-Allow-Headers åçã
Access-Control-Request-Headers: <field-name>[, <field-name>]*
ç¸å ³ç¤ºä¾è§è¿éã
è§è
| è§è |
|---|
| Fetch > # http-access-control-allow-origin > |
æµè§å¨å ¼å®¹æ§
åè§
- CORS é误
- å¯ç¨ CORSï¼å¦ä½å¨æå¡å¨ä¸æ·»å CORS æ¯æ
XMLHttpRequest- Fetch API
- å®ä¼ CORS åï¼ââ交äºç CORS è§£éå¨åçæå¨
- å¦ä½ä¸å¸¦ CORS çè¿è¡ Chrome æµè§å¨
- 卿æï¼ç°ä»£ï¼æµè§å¨ä¸ä½¿ç¨ CORS
- Stack Overflow é¢å¯¹å¸¸è§é®é¢çè§£ç:
- å¦ä½é¿å CORS 颿£è¯·æ±
- å¦ä½å©ç¨ CORS 代çé¿å âNo Access-Control-Allow-Origin headerâ
- å¦ä½ä¿®å¤âAccess-Control-Allow-Origin header must not be the wildcardâ