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


一. Header相關的幾個概念

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

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

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

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

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/Headers

二. 跨域常見問題排查(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;
    }
    ...
}

2.4.  Mixed Content: https域名下請求http接口

Mixed Content: The page at 'https:foo.example.com' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://bar.example.com'. This request has been blocked; the content must be served over HTTPS.

解決方法: 同樣,遇到這一類的問題時,需要仔細閱讀報錯。在報錯里面也寫明了一種解決方法。簡言之,就是要求bar.example.com 必須配置https。這是一種解決方法。當然還有其他的方法,其中之一就是,foo.example.com 也換成http,那么也就沒有被bolck這回事了。

2.5.  net::ERR_FAILED 網絡錯誤

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

POST https:foo.example.com/ net::ERR_FAILED

解決方法: 遇到這類問題,通常是后端應用服務器端資源不能及時響應引起的,此時不應該重點去排查是否因前端跨域引起。可以從下面幾個方面去排查

  1. 檢查與后端應用服務器的網絡響應速度(排除網絡問題)
  2. 單獨請求對應后端應用服務器資源,檢查應用服務器對單一接口的響應速度

排查網絡的工具主要有:ping, traceroute/tracert(路由追蹤),telnet(端口監測),tcpdump/wireshark(抓包分析),這些工具的使用方法可以直接在終端利用man手冊進行查看,如下命令:

$ man ping

也可上網查詢其使用方法,見如下鏈接
ping: https://www.runoob.com/linux/linux-comm-ping.html
traceroute: https://www.runoob.com/linux/linux-comm-traceroute.html
telnet: https://www.runoob.com/linux/linux-comm-telnet.html
tcpdump: https://www.runoob.com/linux/linux-comm-tcpdump.html
...

另外,當被訪問應用服務器端存在限流控制時,如果客戶端頻繁去請求,也可能出現某一時間段的網絡中斷,在排查過程中也應該將這種情況考慮進去


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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM