1. 程式人生 > >跨域 && 解決方法

跨域 && 解決方法

為什麼會出現跨域問題 —— 同源策略

跨域限制僅僅是瀏覽器的行為,伺服器沒有跨域限制。

同時滿足以下三個條件才有可能發生跨域問題:

  1. 瀏覽器限制

  2. 跨域

  3. XMLHttpRequest 請求

跨域的概念:協議、域名、埠都相同才叫同域,否則都叫跨域

出於安全考慮,伺服器不允許ajax跨域獲取資料,但是可以跨域獲取檔案內容。

  • 舉個簡單的例子:在編寫網頁的時候,<img src = ‘www.xxxx.xxxx/’ > URL 不是本域的也可以獲取資料

  • 當我們傳送 XMLHttpRequest 請求的時候,如果請求的是別的域,那麼就會產生跨域問題,客戶端無法獲取伺服器端返回的資料

  • 跨域的問題是發生在 XMLHttpRequest 請求的,也就是說,如果不是 XMLHttpRequest 請求,是不會產生跨域問題的。

解決跨域的方法

從瀏覽器出發

使用相關的引數啟動瀏覽器,解決跨域

通用性極低,不推薦

JSONP 解決跨域

什麼是 JSONP ?

script 標籤中的 src 屬性是可以跨域的。jsonp 是瀏覽器端傳送請求之後,伺服器端包裝好一段 json 資料,並放在一個 callback 函式中,返回一個 js 檔案。瀏覽器端動態引入這個 js 檔案,就會呼叫這個 callback 函式,獲取到資料。

原理:

首先在客戶端註冊一個 callback ,然後把 callback 的名字傳給伺服器。此時,伺服器先生成 json 資料,然後以 javascript 語法的方式,生成 function,function 名字就是傳遞上來的 callback 名稱。最後將 json 資料直接以入參的方式,放置 function 中,這樣就生成 js 語法的文件,返回給客戶端。客戶端瀏覽器,解析 script變遷,並執行返回 javascript 文件,此時資料作為引數,傳入了客戶端預先定義好的 callback 函式裡。

例子:

跨域服務端提供的js指令碼動態生成,這樣呼叫者可以傳一個引數過去告訴跨域服務端“我想要一段呼叫XXX函式的js程式碼,請你返回給我”,於是跨域伺服器就可以按照客戶端的需求來生成js指令碼並響應了。


//跨域伺服器

//檔案:flightResult.php

flightHandler({
    "code":"CA1998",
    "price": 1780,
    "tickets": 5
});

//本地

<script type="text/javascript"> 
    // 得到航班資訊查詢結果後的回撥函式 
    var flightHandler = function(data){
        alert('你查詢的航班結果是:票價 ' + data.price + ' 元,' + '餘票 ' + data.tickets + ' 張。');
    }; 
    // 提供jsonp服務的url地址(不管是什麼型別的地址,最終生成的返回值都是一段javascript程式碼) 
    var url = "跨域伺服器/flightResult.php?code=CA1998&callback=flightHandler";
    // 建立script標籤,設定其屬性 
    var script = document.createElement('script'); 
    script.setAttribute('src', url); 
    // 把script標籤加入head,此時呼叫開始 
    document.getElementsByTagName('head')[0].appendChild(script); 
</script>

缺點:

  1. 只支援 GET 請求而不支援 POST 等其它型別的 HTTP 請求 – 因為 script 標籤,只支援GET

  2. 只支援跨域 HTTP 請求這種情況,不能解決不同域的兩個頁面之間如何進行 JavaScript 呼叫的問題。

CORS 解決跨域問題

一、CORS 簡介:

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源伺服器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

CORS需要瀏覽器和伺服器同時支援。目前,所有瀏覽器都支援該功能,IE瀏覽器不能低於IE10。

整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。

因此,實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊。

二、兩種請求

瀏覽器將 CORS 請求分為兩類:簡單請求和非簡單請求

只要同時滿足一下兩個條件,就屬於簡單請求,反之為非簡單請求

  1. 請求方法是以下三種方法之一:
  • HEAD
  • GET
  • POST
  1. HTTP的頭資訊不超出以下幾種欄位:
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

三、簡單請求

對於簡單請求,瀏覽器直接發出 CORS 請求 :在頭部資訊中,直接加入一個 Origin 欄位

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Origin 欄位用來說明本次請求來自哪個源(協議+域名+埠)。伺服器根據這個值,決定是否同意這次請求。

  1. 如果 Origin 指定的源不在許可範圍內,伺服器會返回一個正常的 http 迴應。這個迴應的頭資訊沒有包含 Access-Control-Allow-Origin 欄位,瀏覽器就會知道出錯了,從而丟擲一個錯誤,被 XMLHttpRequest 的 onerror 回撥函式捕獲。

注意,這種錯誤無法通過狀態碼識別,因為返回的狀態碼可能是 200 。

  1. 在許可範圍之內,伺服器返回的響應,會多出幾個頭資訊的欄位
Access-Control-Allow-Origin: http://api.bob.com  //請求時 Origin 欄位的值或者 * ,表示接受對應域名的請求
Access-Control-Allow-Credentials: true  //表示是否允許傳送 cookie
Access-Control-Expose-Headers: FooBar //拿到指定欄位
Content-Type: text/html; charset=utf-8