天天看點

js的兩種跨域請求——jsonp和cors

什麼是跨域?

廣義的跨域:跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裡跨域是廣義的。

  1. 資源跳轉: A連結、重定向、表單送出
  2. 資源嵌入: 、

狹義的跨域:常說的一種跨域,由浏覽器同源政策限制的一類請求場景。

什麼是同源政策?

同源政策/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入浏覽器,它是浏覽器最核心也最基本的安全功能,如果缺少了同源政策,浏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協定+域名+端口"三者相同,即便兩個不同的域名指向同一個ip位址,也非同源。

同源政策限制以下幾種行為:

  1. Cookie、LocalStorage 和 IndexDB 無法讀取
  2. DOM 和 Js對象無法獲得
  3. AJAX 請求不能發送

常見跨域場景:

URL                                                           說明                                  是否允許通信
http://www.domain.com/a.js
http://www.domain.com/b.js         同一域名,不同檔案或路徑                  允許
http://www.domain.com/lab/c.js

http://www.domain.com:8000/a.js
http://www.domain.com/b.js         同一域名,不同端口                            不允許
 
http://www.domain.com/a.js
https://www.domain.com/b.js        同一域名,不同協定                           不允許
 
http://www.domain.com/a.js
http://192.168.4.12/b.js           域名和域名對應相同ip                               不允許
 
http://www.domain.com/a.js
http://x.domain.com/b.js           主域相同,子域不同                                  不允許
http://domain.com/c.js
 
http://www.domain1.com/a.js
http://www.domain2.com/b.js        不同域名                                             不允許
           

跨域解決方案 -----詳情:https://segmentfault.com/a/1190000011145364

1、 通過jsonp跨域

2、 document.domain + iframe跨域

3、 location.hash + iframe

4、 window.name + iframe跨域

5、 postMessage跨域

6、 跨域資源共享(CORS)

7、 nginx代理跨域

8、 nodejs中間件代理跨域

9、 WebSocket協定跨域

一、CORS(Cross-origin resource sharing 跨域資源共享)

它允許浏覽器向跨源伺服器,發出XMLHttpRequest請求,進而克服了AJAX隻能同源使用的限制。

CORS(Cross-Origin Resource Sharing)跨域資源共享,定義了必須在通路跨域資源時,浏覽器與伺服器應該如何溝通。CORS背後的基本思想就是使用自定義的HTTP頭部讓浏覽器與伺服器進行溝通,進而決定請求或響應是應該成功還是失敗。cors依附于AJAX,通過添加HTTP Hearder部分字段請求與擷取有權限通路的資源。

整個CORS通信過程,都是浏覽器自動完成,不需要使用者參與。對于開發者來說,CORS通信與同源的AJAX通信沒有差别,代碼完全一樣。浏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭資訊,

(Origin:http://www.ajdf.com:80 包括請求頁面的源資訊:協定 域名 端口号)有時還會多出一次附加的請求,但使用者不會有感覺。

是以,實作CORS通信的關鍵是伺服器。隻要伺服器實作了CORS接口,就可以跨源通信。伺服器根據這個頭部資訊來決定是否給予響應。

如果伺服器認為這個請求可以接受,就設定Access-Control-Allow-Origin **(與請求的)相同的 源資訊或者 ***

如果沒有這個頭部,或者有這個頭部但源資訊不比對,浏覽器就駁回(撤銷?)請求。

<script type="text/javascript">
    var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest相容
	xhr.withCredentials = true; // 前端設定是否帶cookie
    xhr.open("GET", "http://segmentfault.com/u/ccd/",true); // 其他域的絕對路徑,也就是你要跨域通路的接口位址
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send();
    
	xhr.onreadystatechange = function() {
	    if (xhr.readyState == 4 && xhr.status == 200) {
	        alert(xhr.responseText);
	    }
	};
</script>
           

伺服器端對于CORS的支援,主要就是通過設定Access-Control-Allow-Origin來進行的。如果浏覽器檢測到相應的設定,就可以允許Ajax進行跨域的通路。

使用場景:對伺服器端的資源要進行一些操作的。

js的兩種跨域請求——jsonp和cors

二、JSONP(json with padding 填充式json)

利用了使用src引用靜态資源時不受跨域限制的機制。其實就是被包含在函數調用中的JSON。

JSONP由兩部分組成:回調函數和資料。回調函數是當響應到來時應該在頁面中調用的函數,而資料就是傳入回調函數中的JSON資料。

jsonp主要在用戶端搞一個回調做一些資料接收與操作的處理,并把這個回調函數名告知服務端,而服務端需要做的是按照javascript的文法把資料放到約定好的回調函數之中即可。

原生:
 <script>
    // 回調執行函數
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>
 // 傳參一個回調函數名給後端,友善後端傳回時執行這個在前端定義的回調函數
 <script src="http://www.a.com:8080/login?user=admin&callback=handleCallback" type='text/javascript'></script>
           
// vue:
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})
           
js的兩種跨域請求——jsonp和cors

使用場景:相容低版本浏覽器。

CORS和JSONP的對比:-----CORS更為先進、友善和可靠。

  1. JSONP的主要優勢在于對浏覽器的支援較好;雖然目前主流浏覽器支援CORS,但IE10以下不支援CORS。jsonp不需要依賴ajax請求受同源政策限制。而是請求完以回調函數的方式回傳結果。
  2. jsonp隻能實作get請求。隻支援跨域http請求的情況,不能解決跨域之間頁面的js調用問題。CORS支援所有類型的HTTP請求,功能完善。(這點JSONP被完虐,但大部分情況下GET已經能滿足需求了)
  3. JSONP的錯誤處理機制并不完善,我們沒辦法進行錯誤處理;而CORS可以通過onerror事件監聽錯誤,可以使用普通的XMLHttpRequest發起請求和獲得資料,并且浏覽器控制台會看到報錯資訊,利于排查。
  4. JSONP隻會發一次請求;而對于複雜請求,CORS會發兩次請求。

參考:https://www.cnblogs.com/chengdabelief/p/6685446.html

參考:https://www.zhihu.com/question/41992168/answer/217903179

參考:https://www.cnblogs.com/Koaler/p/11892205.html

繼續閱讀