解決前端跨域請求的幾種方式


利用 JSONP 實現跨域調用

說道跨域調用,可能大家首先想到的或者聽說過的就是 JSONP 了。

1.1 什么是JSONP

JSONP 是 JSON 的一種使用模式,可以解決主流瀏覽器的跨域數據訪問問題。其原理是根據 XmlHttpRequest 對象受到同源策略的影響,而 <script> 標簽元素卻不受同源策略影響,可以加載跨域服務器上的腳本,網頁可以從其他來源動態產生 JSON 資料。用 JSONP 獲取的不是 JSON 數據,而是可以直接運行的 JavaScript 語句。

1.2 使用 jQuery 集成的 $.ajax 實現 JSONP 跨域調用

下面的例子,我們將 服務器 3000 上的請求頁面的 JavaScript 代碼為:

// 回調函數
function jsonpCallback(data) {
    console.log("jsonpCallback: " + data.name)
}
$("#submit").click(function() {
    var data = {
        name: $("#name").val(),
        id: $("#id").val()
    };
    $.ajax({
        url: 'http://localhost:3001/ajax/deal',
        data: data,
        dataType: 'jsonp',
        cache: false,
        timeout: 5000,
        // jsonp 字段含義為服務器通過什么字段獲取回調函數的名稱
        jsonp: 'callback',
        // 聲明本地回調函數的名稱,jquery 默認隨機生成一個函數名稱
        jsonpCallback: 'jsonpCallback',
        success: function(data) {
            console.log("ajax success callback: " + data.name)
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(textStatus + ' ' + errorThrown);
        }
    });
});

 服務器 3001 上對應的處理函數為:

1 app.get('/ajax/deal', function(req, res) {
2     console.log("server accept: ", req.query.name, req.query.id)
3     var data = "{" + "name:'" + req.query.name + " - server 3001 process'," + "id:'" + req.query.id + " - server 3001 process'" + "}"
4     var callback = req.query.callback  //獲得請求端回調函數
5     var jsonp = callback + '(' + data + ')'
6     console.log(jsonp)
7     res.send(jsonp)
8     res.end()
9 })

這里一定要注意 data 中字符串拼接,不能直接將 JSON 格式的 data 直接傳給回調函數,否則會發生編譯錯誤: parsererror Error: jsonpCallback was not called

 

1.3 使用 <script> 標簽原生實現 JSONP

經過上面的事件,你是不是覺得 JSONP 的實現和 Ajax 大同小異?

其實,由於實現的原理不同,由 JSONP 實現的跨域調用不是通過 XmlHttpRequset 對象,而是通過 script 標簽,所以在實現原理上,JSONP 和 Ajax 已經一點關系都沒有了。看上去形式相似只是由於 jQuery 對 JSONP 做了封裝和轉換。

比如在上面的例子中,我們假設要傳輸的數據 data 格式如下:

{
    name: "chiaki",
    id": "3001"
}

那么數據是如何傳輸的呢?HTTP 請求頭的第一行如下:

GET /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1

可見,即使形式上是用 POST 傳輸一個 JSON 格式的數據,其實發送請求時還是轉換成 GET 請求。

其實如果理解 JSONP 的原理的話就不難理解為什么只能使用 GET 請求方法了。由於是通過 script 標簽進行請求,所以上述傳輸過程根本上是以下的形式:

    
<script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>

這樣從服務器返回的代碼就可以直接在這個 script 標簽中運行了。下面我們自己實現一個 JSONP:

  • 服務器 3000請求頁面的 JavaScript 代碼中,只有回調函數 jsonpCallback:

  • function jsonpCallback(data) {
        console.log("jsonpCallback: "+data.name)
    }

    服務器 3000請求頁面還包含一個 script 標簽:

  • <script src = 'http://localhost:3001/jsonServerResponse?jsonp=jsonpCallback'></script>

    服務器 3001上對應的處理函數:

    1 app.get('/jsonServerResponse', function(req, res) {
    2     var cb = req.query.jsonp //這里得到請求頁面的回調函數
    3     console.log(cb)
    //思考一下為什么這里要這樣寫
    4 var data = 'var data = {' + 'name: $("#name").val() + " - server 3001 jsonp process",' + 'id: $("#id").val() + " - server 3001 jsonp process"' + '};' 5 var debug = 'console.log(data);' //打印var data=""; 6 var callback = '$("#submit").click(function() {' + data + cb + '(data);' + debug + '});' 7 res.send(callback) //返回的是一個點擊按鈕的事件 8 res.end() 9 })

    與上面一樣,我們在所獲取的參數后面加上 “ - server 3001 jsonp process” 代表服務器對數據的操作。從代碼中我么可以看到,處理函數除了根據參數做相應的處理,更多的也是進行字符串的拼接。

  • 2.4 JSONP 總結

    至此,我們了解了 JSONP 的原理以及實現方式,它幫我們實現前端跨域請求,但是在實踐的過程中,我們還是可以發現它的不足:

    1. 只能使用 GET 方法發起請求,這是由於 script 標簽自身的限制決定的。
    2. 不能很好的發現錯誤,並進行處理。與 Ajax 對比,由於不是通過 XmlHttpRequest 進行傳輸,所以不能注冊 success、 error 等事件監聽函數
    3. 使用 CORS 實現跨域調用

      3.1 什么是 CORS?

      Cross-Origin Resource Sharing(CORS)跨域資源共享是一份瀏覽器技術的規范,提供了 Web 服務從不同域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現代版。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以讓網頁設計師用一般的 XMLHttpRequest,這種方式的錯誤處理比 JSONP 要來的好。另一方面,JSONP 可以在不支持 CORS 的老舊瀏覽器上運作。現代的瀏覽器都支持 CORS。

    4. 3.2 CORS 的實現

      還是以 服務器 3000 上的請求頁面向 服務器 3001 發送請求為例。

      • 服務器 3000 上的請求頁面 JavaScript 不變,服務器 3001上對應的處理函數:

      •  1 app.post('/cors', function(req, res) {
         2     res.header("Access-Control-Allow-Origin", "*"); //設置請求來源不受限制
         3     res.header("Access-Control-Allow-Headers", "X-Requested-With");  
         4     res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); //請求方式
         5     res.header("X-Powered-By", ' 3.2.1')
         6     res.header("Content-Type", "application/json;charset=utf-8");
         7     var data = {
         8         name: req.body.name + ' - server 3001 cors process',
         9         id: req.body.id + ' - server 3001 cors process'
        10     }
        11     console.log(data)
        12     res.send(data)
        13     res.end()
        14 })

        3.3 CORS 中屬性的分析

        1. Access-Control-Allow-Origin

          The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify “*” as a wildcard, thereby allowing any origin to access the resource.

        2. Access-Control-Allow-Methods

          Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.

        3. Access-Control-Allow-Headers

          Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

          3.4 CORS 與 JSONP 的對比

          1. CORS 除了 GET 方法外,也支持其它的 HTTP 請求方法如 POST、 PUT 等。
          2. CORS 可以使用 XmlHttpRequest 進行傳輸,所以它的錯誤處理方式比 JSONP 好。
          3. JSONP 可以在不支持 CORS 的老舊瀏覽器上運作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM