輕鬆解決跨域問題

山核桃發表於2018-09-25

跨域:

官方解釋:跨域是指瀏覽器不能執行其他網站的指令碼。它是有瀏覽器的同源策略造成的,是瀏覽器施加的安全限制。

從這裡面我們可以提取到第一個點-->“跨域問題是瀏覽器產生的”
複製程式碼

跨域,又稱跨域名訪問。其中又分為:二級域名跨域、多級 域名跨域、埠號跨域以及協議跨域。

下面說明這幾種跨域,假如一網站是 http://www.abc.com,那麼該網站訪問其他資源的路徑可能是以下幾種:

1、http://abc.com         二級域名跨域
2、http://www.abc.cn      主域名跨域
3、http://www.def.com     主域名跨域
4、https://www.abc.com    協議跨域複製程式碼

解決跨域的方法:

一、jsonp 跨域

jsonp跨域是利用,在瀏覽器當中,img標籤的src、以及script標籤的src、以及link標籤的href不受瀏覽器同源政策的限制。繞過ajax去請求資料。既然如此,我們就可以利用動態的建立script標籤的方式,去跨域請求資料了。

這裡我使用node做示例,那麼我就利用express來建立一個jsonp資料,之後就來請求這個資料即可

app.get('/jsonp', (req, res, next) => {
    res.jsonp({
        data: 'this is a jsonp data'
    })
})複製程式碼

既然jsonp是利用script標籤去請求資料,那麼我們就需要動態建立script標籤

第一步:定義處理函式,用來處理接收到的資料

function getData(res) {
    console.log(res)
}複製程式碼

第二步:建立script標籤,去請求資料

let jsonp = document.createElement('script')
jsonp.src = 'http://localhost:3000/jsonp?callback=getData'複製程式碼

這裡jsonp預設使用callback作為請求引數

在這之後資料會被列印出來。

jsonp的優勢:相容性比較好(幾乎所有瀏覽器都支援script標籤)

jsonp的劣勢:jsonp只支援get請求

二、cors跨域

CORS需要瀏覽器和伺服器同時支援,目前幾乎所有瀏覽器都支援CORS,IE不能低於IE10。整個CORS跨域的過程,前端都是瀏覽器自動完成的,瀏覽器一旦發現ajax請求跨域資源,就會自動新增一些附加的頭資訊,有時還會多一次試探性的OPTIONS請求。

CORS又分為簡單請求和非簡單請求

① 簡單請求:

要同時滿足以下幾個條件:

1、請求方式是   HEAD、GET、POST其中的一個

2、http的請求頭不超出以下幾種資訊:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type

3、Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

簡單請求時瀏覽器會自動帶上一個請求頭" Origin: 客戶端域名 ”

當瀏覽器接收到伺服器返回的響應時,會對響應頭進行分析。如果 存在 Access-Control-Allow-Origin:“客戶端域名”;那麼瀏覽器就會把請求到的資料返回給ajax物件,否則就會觸發ajax的onerror事件,丟擲一個錯誤異常

② 非簡單請求

對於非簡單請求一般分為以下步驟

第一步:

瀏覽器先發出一個options的請求。並且包含一些頭部資訊:

Origin:客戶端域名Access-Control-Request-Headers: content-type (表明客戶端傳送的請求頭資料)Access-Control-Request-Method: POST (表明客戶端傳送的請求型別)複製程式碼

第二步:

伺服器返回options請求

Access-Control-Allow-Origin:允許跨域的域名(可以是指定域名,也可以是全域名“*”)Access-Control-Allow-Headers: “與客戶端對應”Access-Control-Allow-Method: 與客戶端的對應或者大於客戶端複製程式碼

第三步:

客戶端檢查options請求的響應頭。如

Access-Control-Allow-Origin:允許跨域的域名Access-Control-Allow-Headers: “與客戶端對應”Access-Control-Allow-Method: 與客戶端的對應或者大於客戶端複製程式碼

如果伺服器的響應頭與瀏覽器的請求頭對應了,瀏覽器會正式發出請求,伺服器對請求做出響應,並帶上之前的請求頭完成跨域。

不過雖然上面的 對響應頭的設定已經可以實現跨域了不過會造成session的丟失,對此我們需要設定另一個請求頭引數Access-Control-Allow-Credentials = true,在預設false情況下客戶端是不會攜帶cookies到伺服器的。

session丟失的解決:

在響應頭裡邊,指定唯一的允許跨域的域名。服務端在響應頭裡邊。指定Access-Control-Allow-Credentials:true,以及客戶端的ajax物件,必須指withCredentials: true;

更好的瞭解cors跨域的同學可以看看阮一峰老師的《跨域資源共享 CORS 詳解

下面是express實現cors跨域,瀏覽器端的請求頭瀏覽器會自動新增

router.options('/getCorsData',(req,res)=>{
    res.header('Access-Control-Allow-Origin','*')   //設定允許訪問的域名 * 代表所有
    res.header('Access-Control-Allow-Headers','content-type')
    res.header('Access-Control-Allow-Method','OPTIONS,POST,PUT')    
    res.header('Access-Control-Allow-Credentials','true')
    res.send(200)
})
複製程式碼

三、代理跨域

代理跨域的道理很簡單,既然跨域是因為瀏覽器的同源策略引起的,那麼非同源資源不交給瀏覽器去直接請求,而是讓同源伺服器去請求再返回給瀏覽器

輕鬆解決跨域問題

express程式碼示例:

app.get('/getdata', (req, res) => {
    request('http://localhost:3000/getCors', (err, response, body) => {
        res.json(response)
    })
})複製程式碼

以上程式碼是我是開了兩個伺服器模擬的一個 3001 埠另一個是3000埠,屬於埠跨域,在3001的頁面中去訪問getdata時伺服器向3000埠請求資料,並把資料返回給頁面,完成跨域。

但一般我們都是去使用中介軟體去完成代理跨域。比如 http-proxy-middleware,有興趣的可以去github中檢視使用方法。

總結

知識在於積累,生命在於折騰,有錯誤的請留言指出,批評使我進步


相關文章