AJAX-跨域請(qǐng)求

1、什么是跨域請(qǐng)求

瀏覽器均默認(rèn)開啟了同源策略,它指Ajax請(qǐng)求所在的頁面和被請(qǐng)求的頁面在域名、端口均相同才能被訪問,否則會(huì)提示如下錯(cuò)誤:

XMLHttpRequest cannot load xxxxxxx is not allowed by 
Access-Control-Allow-Origin.

2、JSONP解決方案

2.1 JSONP原理

JSONP 不是真正的AJAX請(qǐng)求,是利用script的src可可以跨域的特性,動(dòng)態(tài)加載一段script腳本,腳本中包含需要的信息。

2.2 基礎(chǔ)代碼實(shí)現(xiàn)

html源代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp跨域</title>
    <script type="text/javascript">
        function callbak(rs){
            alert(rs.data);
        }
    </script>
    <script src="http://127.0.0.1:8080"></script>
</head>
<body>
</body>
</html>

node js 服務(wù)器代碼:

//調(diào)用http模塊
var http = require('http'); 
var server = http.createServer(function (request, response) {
     response.writeHead(200, {
        'Content-Type': 'application/javascript'
    });
    response.write("callbak({'data':'jsonp'});");
    response.end();
   
});
server.listen(8080);
//打印日志
console.log('Http server is started. http://127.0.0.1:8080');

注意:
(1)函數(shù)名callbak 前端與后端需要一致
(2)服務(wù)器反饋的數(shù)據(jù)類型application/javascript 類型

2.3 JSONP 公用函數(shù)封裝。

前端代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp跨域</title>
</head>
<body id="body">
</body>
<!-- 主要要在body之后,否則document.body為null-->
<script type="text/javascript">
        function jsonp(url,callback){
            //動(dòng)態(tài)生成函數(shù)名稱
            var funcName= "callback"+new Date().getTime();
            //添加callback參數(shù)到url中(假設(shè)url中沒有其他參數(shù))
            url = url + "?callback="+funcName;
            //設(shè)置全局函數(shù)是傳人行數(shù)
            window[funcName] = callback;
            //創(chuàng)建Script標(biāo)簽
            var script = document.createElement("script");
            script.src = url;
            //添加到body中
            var body = document.body;
            body.appendChild(script);
            //動(dòng)態(tài)標(biāo)簽加載完成
            script.onload = function(){
                //刪除script標(biāo)簽
                body.removeChild(script);
                //刪除全局函數(shù)
                window[funcName] = null;
            }
        }
        var url = "http://127.0.0.1:8080";
        jsonp(url,function(rs){
            alert(rs.data);
        });
    </script>
</html>

node js 后端代碼:

//調(diào)用http模塊
var http = require('http'); 
var url = require('url');
var server = http.createServer(function (request, response) {
     response.writeHead(200, {
        'Content-Type': 'application/javascript'
    });
    //請(qǐng)求參數(shù)轉(zhuǎn)換為json格式
    var arg = url.parse(request.url, true).query;
    //獲取回調(diào)方法名稱
    var funcName = arg.callback;
    response.write(funcName + "({'data':'jsonp'});");
    response.end();
   
});
server.listen(8080);
//打印日志
console.log('Http server is started. http://127.0.0.1:8080');

3、CROS解決方案

3.1 CROS簡(jiǎn)單

CORS需要瀏覽器和服務(wù)器同時(shí)支持。只有支持XmlHttpRequest Level2的瀏覽器才支持。
??整個(gè)CORS通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發(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接口,就可以跨源通信。

3.2 CROS服務(wù)器端設(shè)置

(1)Access-Control-Allow-Origin
??該字段是必須的。它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。

(2)Access-Control-Request-Method
??該字段是必須的,列出瀏覽器的CORS請(qǐng)求會(huì)用到哪些HTTP方法。

**(3)Access-Control-Expose-Headers **
??該字段可選。CORS請(qǐng)求時(shí),XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。
**(4)Access-Control-Allow-Credentials **
??該字段可選。它的值是一個(gè)布爾值,表示是否允許發(fā)送Cookie。默認(rèn)情況下,Cookie不包括在CORS請(qǐng)求之中。設(shè)為true,即表示服務(wù)器明確許可,Cookie可以包含在請(qǐng)求中,一起發(fā)給服務(wù)器。這個(gè)值也只能設(shè)為true,如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可。
(5)Access-Control-Max-Age
??該字段可選,用來指定本次預(yù)檢請(qǐng)求的有效期,單位為秒,在此期間,不用發(fā)出另一條預(yù)檢請(qǐng)求。

3.3 CROS跨域Cookie

CORS請(qǐng)求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息。如果要把Cookie發(fā)到服務(wù)器,一方面要服務(wù)器同意,指定Access-Control-Allow-Credentials字段,設(shè)置** Access-Control-Allow-Credentials: true**。

Access-Control-Allow-Credentials: true

另一方面,開發(fā)者必須在AJAX請(qǐng)求中打開withCredentials屬性。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

否則,即使服務(wù)器同意發(fā)送Cookie,瀏覽器也不會(huì)發(fā)送。或者,服務(wù)器要求設(shè)置Cookie,瀏覽器也不會(huì)處理。但是,如果省略withCredentials設(shè)置,有的瀏覽器還是會(huì)一起發(fā)送Cookie。這時(shí),可以顯式關(guān)閉withCredentials,設(shè)置withCredentials=false;
特別注意
需要注意的是,如果要發(fā)送Cookie,Access-Control-Allow-Origin就不能設(shè)為星號(hào),必須指定明確的、與請(qǐng)求網(wǎng)頁一致的域名。同時(shí),Cookie依然遵循同源政策,只有用服務(wù)器域名設(shè)置的Cookie才會(huì)上傳,其他域名的Cookie并不會(huì)上傳,且(跨源)原網(wǎng)頁代碼中的document.cookie也無法讀取服務(wù)器域名下的Cookie。

3.4 CROS預(yù)檢

(1)預(yù)檢查概述
??非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP查詢請(qǐng)求,稱為"預(yù)檢"請(qǐng)求(preflight)。瀏覽器先詢問服務(wù)器,當(dāng)前網(wǎng)頁所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動(dòng)詞和頭信息字段。只有得到肯定答復(fù),瀏覽器才會(huì)發(fā)出正式的XMLHttpRequest請(qǐng)求,否則就報(bào)錯(cuò)。
(2)預(yù)檢查請(qǐng)求
??"預(yù)檢"請(qǐng)求用的請(qǐng)求方法是OPTIONS,表示這個(gè)請(qǐng)求是用來詢問的。頭信息里面,關(guān)鍵字段是Origin,表示請(qǐng)求來自哪個(gè)源。除了Origin字段,"預(yù)檢"請(qǐng)求的頭信息包括兩個(gè)特殊字段。Access-Control-Request-MethodAccess-Control-Request-Headers
(3)預(yù)檢查響應(yīng)
??服務(wù)器收到"預(yù)檢"請(qǐng)求以后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認(rèn)允許跨源請(qǐng)求,就可以做出回應(yīng)。回應(yīng)的內(nèi)容參考服務(wù)端配置。

3.5 CROS 正常請(qǐng)求與回應(yīng)

一旦服務(wù)器通過了"預(yù)檢"請(qǐng)求,以后每次瀏覽器正常的CORS請(qǐng)求,就都跟簡(jiǎn)單請(qǐng)求一樣,會(huì)有一個(gè)Origin頭信息字段。服務(wù)器的回應(yīng),也都會(huì)有一個(gè)Access-Control-Allow-Origin頭信息字段。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. 所謂跨域 跨域是一種瀏覽器同源安全策略,也即瀏覽器單方面限制腳本的跨域訪問。很多人可能誤認(rèn)為資源跨域時(shí)無法請(qǐng)...
    blurooo閱讀 6,193評(píng)論 11 54
  • CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)。 ...
    奇特思維家閱讀 1,140評(píng)論 0 3
  • 題目1.什么是同源策略? 同源策略(Same origin Policy): 瀏覽器出于安全方面的考慮,只允許與本...
    FLYSASA閱讀 1,752評(píng)論 0 6
  • 1. 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScri...
    cbw100閱讀 6,395評(píng)論 2 86
  • gank.io 感謝 http://gank.io 提供的api幫助完成這個(gè)app該項(xiàng)目完全開源,單純?yōu)榱藢W(xué)習(xí)與交...
    jzhu085閱讀 327評(píng)論 0 2