天天看點

跨域監聽 iframe src_跨域的幾種實作方式|精選部落格使用降域實作跨域

一、背景

同源政策

同源政策可以了解為浏覽器的一種安全機制,浏覽器隻允許與本域下的接口進行互動。不同源的用戶端在沒有明确授權的情況下,不能讀寫服務端的資源。

什麼是不同源呢:

  • 不同的協定 例:http/https
  • 不同的域名
  • 不同的端口
  • 不同的二級域名 例:http://a.baidu.com、http://b.baidu.com(不然哪來的降域呢)

補充點

在出現跨域問題時,浏覽器究竟在哪一步進行了攔截?用戶端請求時?伺服器不做出響應?還是伺服器響應後浏覽器拒絕的響應??

跨域監聽 iframe src_跨域的幾種實作方式|精選部落格使用降域實作跨域

image.png

跨域監聽 iframe src_跨域的幾種實作方式|精選部落格使用降域實作跨域

image.png

測試發現,在用戶端和服務端不同源的情況下,服務端其實是有響應的,在此時是浏覽器的同源政策拒絕了響應,認為這樣不安全。

二、解決跨域問題

1. JSONP(JSON with Padding)

  • 原理: 在HTML中用script标簽在加載其他域下的js,那麼JSON就是利用這一特性來請求服務端,進而避免了ajax請求出現的跨域問題
  • 具體實施

(1) 定義資料處理函數_fun

(2) 建立script标簽,并添加src位址來請求服務端接口,在src尾端加上自定義參數callback=_fun

(3) 服務端收到請求後,根據get參數判斷傳回拼接的字元串:'_fun(data)'

(4) fun(data)會放到script标簽作為js執行,那麼此時就會調用fun函數,将data作為函數的參數

  • 相應代碼

用戶端:

擷取天氣

function weather(data){

console.log(data)

}

document.querySelector('.btn').addEventListener('click', function(){

var script = document.createElement('script')

script.src = 'http://localhost:8080/getWeather?callback=weather&a=b'

document.head.appendChild(script)

document.head.removeChild(script)

})

服務端:

'/getWeather':function(req, resp){

resp.writeHead(200, 'success')

if(req.query.callback){

var res = JSON.stringify({'beijing':'sunny'})

resp.end(req.query.callback+'('+res+')')

}else{

resp.end(JSON.stringify({'beijing':'rain'}))

}

}

2. CORS(Cross-Origin Resource Sharing)跨域資源共享

CORS,跨域資源共享,是一種ajax跨域請求資源的方式。(幾乎所有浏覽器都支援,但是ie必須10以上。)

(1) 當用戶端使用XMLHttpRequest發送請求時,浏覽器發現請求不符合同源政策,會加上一個請求頭:origin;

擷取天氣

document.querySelector('.btn').addEventListener('click', function(){

var xhr = new XMLHttpRequest()

xhr.open('get', 'http://www.b.com:8080/getWeather', true)

xhr.onload = function(){

console.log(xhr.responseText)

}

xhr.send()

})

跨域監聽 iframe src_跨域的幾種實作方式|精選部落格使用降域實作跨域

image.png

(2) 在服務端收到請求并響應時,設定在響應結果加上Access-Control-Allow-Origin;

'/getWeather':function(req, resp){

resp.setHeader('Access-Control-Allow-Origin','http://www.a.com:8080')

resp.writeHead(200, 'success')

resp.end(JSON.stringify({'beijing':'rain'}))

}

跨域監聽 iframe src_跨域的幾種實作方式|精選部落格使用降域實作跨域

image.png

或者response.setHeader('Access-Control-Allow-Origin',''),‘’代表接收所有位址的請求。

(3) 此時浏覽器判斷如果該響應頭包含請求頭origin的值,就接收響應,否則拒絕就拿不到響應資料。

CORS與JSONP差別:

  1. CORS與JSONP的使用目的相同,但是比JSONP更強大;
  2. JSONP隻支援GET請求,CORS支援所有類型的HTTP請求;
  3. JSONP的優勢在于支援老式浏覽器,以及可以向不支援CORS的網站請求資料。

3. 降域

會發現當頁面嵌入iframe的時候,在不同源的二級域名情況下我們是不能通過js操作iframe裡面的内容的,這時可以通過降域達到目的。

使用降域實作跨域

//URL: http://a.test.com:8080/a.html

document.querySelector('.main input').addEventListener('input', function(){

console.log(this.value);

window.frames[0].document.querySelector('input').value = this.value;

})

document.domain = "test.com"

4. postMassage

在某些情況下iframe裡面的服務端是願意提供一些接口的,這時就用到了

postMessage(),postMessage()方法允許來自不同源的腳本采用異步方式進行有限的通信,可以實作跨文本檔、多視窗、跨域消息傳遞。

//URL:http://www.a.com:8080/a.html

window.frames[0].postMessage(data,'*')

//URL:http://www.b.com:8080/b.html

window.addEventListener('message',function(e){

console.log(e.data)

})

5. 服務端中轉跨域

如果對方伺服器不提供跨域支援怎麼辦呢?這是可以自己搭建server請求中轉(在服務端不存在同源政策限制)。

現在我有一個天氣預報頁面http://www.a.com,需要向http://www.weather.com接口擷取天氣資料,但是這個接口不支援JSONP和CORS跨域,那麼可以這樣做:

  1. 搭建伺服器,建立一個擷取天氣的接口http://www.b.com
  2. 設定接口http://www.b.com的響應頭Access-Control-Allow-Origin:http://www.a.com
  3. 頁面http://www.a.com向http://www.b.com發請求
  4. http://www.b.com收到請求後,向http://www.weather.com擷取天氣資料,然後将天氣資料傳回給http://www.a.com