跨域方式具體實(shí)現(xiàn)

一.CORS

1.CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。

整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。
因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。

2.兩種請(qǐng)求方式

瀏覽器將CORS請(qǐng)求分成兩類:簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)。

只要同時(shí)滿足以下兩大條件,就屬于簡(jiǎn)單請(qǐng)求。

(1) 請(qǐng)求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求。

瀏覽器對(duì)這兩種請(qǐng)求的處理,是不一樣的。

3基本流程

  • 簡(jiǎn)單請(qǐng)求: 正常發(fā)送Ajax請(qǐng)求=>瀏覽器檢測(cè)到此請(qǐng)求為跨域請(qǐng)求自動(dòng)增加一個(gè)origin字段=>服務(wù)器根據(jù)這個(gè)值決定是否同意這次請(qǐng)求=>瀏覽器得到回應(yīng),根據(jù)返回的頭信息沒(méi)有包含Access-Control-Allow-Origin字段判斷本次CORS請(qǐng)求是否成功
GET /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
Accept-Language: en-USConnection: keep-alive
User-Agent: Mozilla/5.0...

上面的頭信息中,Origin字段用來(lái)說(shuō)明,本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 域名 + 端口)。服務(wù)器根據(jù)這個(gè)值,決定是否同意這次請(qǐng)求。

  • 非簡(jiǎn)單請(qǐng)求:非簡(jiǎn)單請(qǐng)求是那種對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
    非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP查詢請(qǐng)求,稱為"預(yù)檢"請(qǐng)求(preflight)。
OPTIONS /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

瀏覽器發(fā)出預(yù)檢請(qǐng)求=> 服務(wù)器回應(yīng)預(yù)檢請(qǐng)求==> 服務(wù)器同意則會(huì)返回一個(gè)帶Access-Control-Allow-Origin頭信息的HTTP回應(yīng)=> 瀏覽器判斷預(yù)檢請(qǐng)求是否被允許 =>如果預(yù)檢請(qǐng)求被通過(guò),以后每次的非簡(jiǎn)單請(qǐng)求,就都和簡(jiǎn)單請(qǐng)求一樣
參考文章

二.JSONP

JSONP的實(shí)現(xiàn)思路
1.前端創(chuàng)建script標(biāo)記,設(shè)置src,添加到head中(可以往body中添加)
2.后臺(tái)返回一個(gè)js變量jsonp,這個(gè)jsonp就是請(qǐng)求后的JSON數(shù)據(jù)
3.回調(diào)完成后刪除script標(biāo)記(還有一些清理工作如避免部分瀏覽器內(nèi)存泄露等)
范例:

//服務(wù)器代碼
var http = require('http');  
var urllib = require('url');  
  
var port = 10011;  
var data = {'name': 'jifeng', 'company': 'taobao'};  
  
http.createServer(function(req, res){  
  var params = urllib.parse(req.url, true);  
  console.log(params);  
  if (params.query && params.query.callback) {  
    //console.log(params.query.callback);  
    var str =  params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp  
    res.end(str);  
  } else {  
    res.end(JSON.stringify(data));//普通的json  
  }       
}).listen(port, function(){  
  console.log('server is listening on port ' + port);    
})  

<html>    
<head>    
  <script src="http://code.jquery.com/jquery-latest.js"></script>    
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">    
</head>    
<body>    
<script type="text/javascript">    
function get_jsonp() {    
  $.getJSON("http://10.232.36.110:10011?callback=?",    //瀏覽器端代碼,jQuery實(shí)現(xiàn)
  function(data) {  
    $('#result').val('My name is: ' + data.name);    
  });    
}    
</script>    
<a href="javascript:get_jsonp();">Click me</a><br />    
<textarea id="result" cols="50" rows="3"></textarea>    
</body>    
</html>  

三.postmanage

HTML5中最酷的新功能之一就是 跨文檔消息傳輸Cross Document Messaging。下一代瀏覽器都將支持這個(gè)功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經(jīng)使用了這個(gè)功能,用postMessage支持基于web的實(shí)時(shí)消息傳遞。

otherWindow.postMessage(message, targetOrigin);
otherWindow: 對(duì)接收信息頁(yè)面的window的引用??梢允琼?yè)面中iframe的contentWindow屬性;window.open的返回值;通過(guò)name或下標(biāo)從window.frames取到的值。
message: 所要發(fā)送的數(shù)據(jù),string類型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
a.com/index.html中的代碼:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若寫成'http://b.com/c/proxy.html'效果一樣
                                        // 若寫成'http://c.com'就不會(huì)執(zhí)行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代碼:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通過(guò)origin屬性判斷消息來(lái)源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 彈出"I was there!"
            alert(event.source);  // 對(duì)a.com、index.html中window對(duì)象的引用
                                  // 但由于同源策略,這里event.source不可以訪問(wèn)window對(duì)象
        }
    }, false);
</script>

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容