跨域請求中常見的幾個問題

一. Header相關的幾個概念

CORS: 跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP頭來告訴瀏覽器  讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。當一個資源從與該資源自己所在的服務器不一樣的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。html

出於安全緣由,瀏覽器限制從腳本內發起的跨源HTTP請求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 這意味着使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非響應報文包含了正確CORS響應頭。web

origin: web的origin 被定義爲由協議,域和端口組成的 URL訪問。僅當協議,域和端口所有匹配,兩對象才具備相同的origin。shell

Access-Control-Allow-Origin: 該響應是否能夠與來自給定的請求代碼共享origin。  segmentfault

Access-Control-Allow-Origin:*  #容許任何源的代碼訪問資源
Access-Control-Allow-Origin: https://developer.mozilla.org  #容許請求來自https://developer.mozilla.org 的代碼訪問資源。

Access-Control-Allow-Methods: 在對preflight request(預檢請求)的應答中明確了客戶端所要訪問的資源容許使用的方法或方法列表跨域

Access-Control-Allow-Methods POST,GET,OPTIONS,PUT

Access-Control-Allow-Headers:  用於preflight request(預檢請求)種,列出了將會在正式請求的Access-Control-Expose-Headers 字段中出現的首部信息,用於響應包含在Access-Control-Request-Headers 首部的預檢請求。瀏覽器

Access-Control-Allow-Headers Content-Type,access-control-allow-credentials,access-control-allow-origin

Access-Control-Max-Age: 這個響應首部表示preflight request(預檢請求)的返回結果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 能夠被緩存多久。緩存

Access-Control-Max-Age: 600 #

CORS中的預檢請求(option): 在 CORS 中,可使用 OPTIONS 方法發起一個預檢請求(通常都是瀏覽檢測到請求跨域時,會自動發起),以檢測實際請求是否能夠被服務器所接受。預檢請求報文中的 Access-Control-Request-Method首部字段告知服務器實際請求所使用的 HTTP 方法;Access-Control-Request-Headers 首部字段告知服務器實際請求所攜帶的自定義首部字段。服務器基於從預檢請求得到的信息來判斷,是否接受接下來的實際請求。安全

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

服務器所返回的 Access-Control-Allow-Methods 首部字段將全部容許的請求方法告知客戶端。該首部字段與 Allow 相似,但只能用於涉及到 CORS 的場景中。服務器

想要了解更多的http header信息 請訪問 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headerscookie

二. 跨域常見問題排查(CORS場景)

2.1. 未配置 Access-Control-Allow-Origin。

Access to XMLHttpRequest at 'http://foo1.example.com/' from origin 'http://foo2.example.com/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

解決方法: 在域爲foo1.example.com 的虛擬主機添加 Access-Control-Allow-Origin 值爲http://foo2.example.com。

server {
    ...
    server_name foo1.example.com;
    ...
    add_header 'Access-Control-Allow-Origin' 'http://foo2.example.com';
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';

    if ($request_method = "OPTIONS")  {
        return 204;
    }
    ...
}

2.2. 跨域訪問

Access to XMLHttpRequest at 'http://foo1.example.com/' from origin 'http://foo3.example.com/' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://foo2.example.com/' that is not equal to the supplied origin.

 解決方法:請注意觀察上述報錯, Access-Control-Allow-Origin 已經至少有一個值爲http://foo2.example.com 的設定。因此如今配置一個容許多源訪問的配置。

server {
    ...
    server_name foo1.example.com;
    ...
    if ( $http_origin ~ .*.(example|aldwx).(net|com)) {
        set $other_domain $http_origin;
    }

    add_header Access-Control-Allow-Origin $other_domain;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';

    if ($request_method = "OPTIONS")  {
        return 204;
    }
    ...
}

2.3.  Access-Control-Allow-Headers 中首部缺失

Access to XMLHttpRequest at 'http://foo1.example.com/' from origin 'http://foo2.example.com/' has been blocked by CORS policy: Request header field <u>cookies</u> is not allowed by Access-Control-Allow-Headers in preflight response.

解決方法: 遇到這一類的問題時,須要仔細閱讀報錯,在報錯裏面基本已經寫明瞭答案。例如上面的這個報錯信息。域foo2.example.com 請求域foo1.example.com 時,因首部cookies 未包含在 Access-Control-Allow-Headers 中,因此foo1沒法響應客戶端請求。而且這一類問題可能同時會出現幾個首部缺失的請求,可是報錯是單個出現,因此呢,要仔細閱讀錯誤。下面也是其中一個報錯

Access to XMLHttpRequest at 'http://foo1.example.com/' from origin 'http://foo2.example.com/' has been blocked by CORS policy: Request header field <u>access-control-allow-credentials</u> is not allowed by Access-Control-Allow-Headers in preflight response.
server {
    ...
    server_name foo1.example.com;
    ...
     
    if ( $http_origin ~ .*.(example|aldwx).(net|com)) {
        set $other_domain $http_origin;
    }

    add_header Access-Control-Allow-Origin $other_domain;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'access-control-allow-credentials,cookies,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    if ($request_method = "OPTIONS")  {
        return 204;
    }
    ...
}

參考文章:
Nginx配置跨域請求 Access-Control-Allow-Origin *

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

相關文章
相關標籤/搜索