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

利用 JSONP 實現跨域調用前端

說道跨域調用,可能你們首先想到的或者據說過的就是 JSONP 了。jquery

1.1 什麼是JSONP

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

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

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

// 回調函數
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 作了封裝和轉換。app

好比在上面的例子中,咱們假設要傳輸的數據 data 格式以下:cors

{
    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 的老舊瀏覽器上運做。
相關文章
相關標籤/搜索