天天看點

AJAX-跨域請求

1、什麼是跨域請求

浏覽器均預設開啟了同源政策,它指Ajax請求所在的頁面和被請求的頁面在域名、端口均相同才能被通路,否則會提示如下錯誤:

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

2、JSONP解決方案

2.1 JSONP原理

JSONP 不是真正的AJAX請求,是利用script的src可可以跨域的特性,動态加載一段script腳本,腳本中包含需要的資訊。

2.2 基礎代碼實作

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 伺服器代碼:

//調用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)函數名callbak 前端與後端需要一緻

(2)伺服器回報的資料類型application/javascript 類型

2.3 JSONP 公用函數封裝。

前端代碼:

<!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){
            //動态生成函數名稱
            var funcName= "callback"+new Date().getTime();
            //添加callback參數到url中(假設url中沒有其他參數)
            url = url + "?callback="+funcName;
            //設定全局函數是傳人行數
            window[funcName] = callback;
            //建立Script标簽
            var script = document.createElement("script");
            script.src = url;
            //添加到body中
            var body = document.body;
            body.appendChild(script);
            //動态标簽加載完成
            script.onload = function(){
                //删除script标簽
                body.removeChild(script);
                //删除全局函數
                window[funcName] = null;
            }
        }
        var url = "http://127.0.0.1:8080";
        jsonp(url,function(rs){
            alert(rs.data);
        });
    </script>
</html>
           

node js 後端代碼:

//調用http子產品
var http = require('http'); 
var url = require('url');
var server = http.createServer(function (request, response) {
     response.writeHead(200, {
        'Content-Type': 'application/javascript'
    });
    //請求參數轉換為json格式
    var arg = url.parse(request.url, true).query;
    //擷取回調方法名稱
    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簡單

CORS需要浏覽器和伺服器同時支援。隻有支援XmlHttpRequest Level2的浏覽器才支援。

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

  是以,實作CORS通信的關鍵是伺服器。隻要伺服器實作了CORS接口,就可以跨源通信。

3.2 CROS伺服器端設定

(1)Access-Control-Allow-Origin

  該字段是必須的。它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任意域名的請求。

(2)Access-Control-Request-Method

  該字段是必須的,列出浏覽器的CORS請求會用到哪些HTTP方法。

**(3)Access-Control-Expose-Headers **

  該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法隻能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers裡面指定。

**(4)Access-Control-Allow-Credentials **

  該字段可選。它的值是一個布爾值,表示是否允許發送Cookie。預設情況下,Cookie不包括在CORS請求之中。設為true,即表示伺服器明确許可,Cookie可以包含在請求中,一起發給伺服器。這個值也隻能設為true,如果伺服器不要浏覽器發送Cookie,删除該字段即可。

(5)Access-Control-Max-Age

  該字段可選,用來指定本次預檢請求的有效期,機關為秒,在此期間,不用發出另一條預檢請求。

3.3 CROS跨域Cookie

CORS請求預設不發送Cookie和HTTP認證資訊。如果要把Cookie發到伺服器,一方面要伺服器同意,指定Access-Control-Allow-Credentials字段,設定** Access-Control-Allow-Credentials: true**。

Access-Control-Allow-Credentials: true
           

另一方面,開發者必須在AJAX請求中打開withCredentials屬性。

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

否則,即使伺服器同意發送Cookie,浏覽器也不會發送。或者,伺服器要求設定Cookie,浏覽器也不會處理。但是,如果省略withCredentials設定,有的浏覽器還是會一起發送Cookie。這時,可以顯式關閉withCredentials,設定withCredentials=false;

特别注意

需要注意的是,如果要發送Cookie,Access-Control-Allow-Origin就不能設為星号,必須指定明确的、與請求網頁一緻的域名。同時,Cookie依然遵循同源政策,隻有用伺服器域名設定的Cookie才會上傳,其他域名的Cookie并不會上傳,且(跨源)原網頁代碼中的document.cookie也無法讀取伺服器域名下的Cookie。

3.4 CROS預檢

(1)預檢查概述

  非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。浏覽器先詢問伺服器,目前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊字段。隻有得到肯定答複,浏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。

(2)預檢查請求

  "預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭資訊裡面,關鍵字段是Origin,表示請求來自哪個源。除了Origin字段,"預檢"請求的頭資訊包括兩個特殊字段。Access-Control-Request-Method和 Access-Control-Request-Headers

(3)預檢查響應

  伺服器收到"預檢"請求以後,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以後,确認允許跨源請求,就可以做出回應。回應的内容參考服務端配置。

3.5 CROS 正常請求與回應

一旦伺服器通過了"預檢"請求,以後每次浏覽器正常的CORS請求,就都跟簡單請求一樣,會有一個Origin頭資訊字段。伺服器的回應,也都會有一個Access-Control-Allow-Origin頭資訊字段。

下一篇: AJAX-基礎

繼續閱讀