跨域原理以及跨域解決方案

weixin_34402408發表於2017-10-15

寫在前面的話

在火熱的網際網路IT時代,越來越多的前端開發工程師和H5開發工程師都會遭遇到人(猿)生中一個名詞:跨域,尤其是新手第一次接觸這個東西時,頓感手足無措。本篇文章將會對跨域從基本概念到詳細應用進行一一解讀,廢話不多,直接走起....

跨域到底是什麼?

先上張圖,給各位壓壓驚...

3091895-aed506cf722e4989.png
跨域錯誤提示資訊

是不是又看到了熟悉的 No 'Access-Control-Allow-Origin' (這是跨域的經典標誌), 驚不驚喜,意不意外,是不是很熟悉!

認識URL網址

URL地址: http://www.justbecoder.com:80/article/index.html
    http                                  超文字傳輸協議
    www.justbecoder.com                   域名
    80                                    埠號
    article/index.html                    檔案目錄與檔名      

同源策略

概念

同源策略是瀏覽器最核心也是最基本的的安全功能,是指我們在傳送網路請求時請求必須要遵守同源策略,即域名、協議、埠號都要相同

意義

是為了保證使用者資訊的安全,防止惡意的網站竊取資料。

觸發跨域的場景以及原因

當同源策略中的 域名、協議、埠號有一樣不相同時,都會觸發跨域

假定當前在的網址是: http://www.justbecoder.com:80/,當我向以下網址傳送請求時都會觸發跨域
    url: https://www.justbecoder.com:80/   // 協議不同 --- 喂,老婆,我聽不懂呀,你說話加密啦!
    url: http://www.baidu.com:80/          // 域名不同 --- 哎呀,菇涼認錯認了,你不是我老婆
    url: http://www.justbecoder.com:8080/  // 埠不同 --- 是你老婆沒錯,但是你沒有找對你老婆身上的門啊

我們必須是用跨域嗎?

現在網站的功能越來越多,網站中的圖片、視訊、資料庫有可能都不在同一臺伺服器上,不同協議、不同域名、不同埠號的伺服器進行相互請求和響應是必然的,所以跨域一定是會使用到的!

如何應用和解決跨域

問題場景:

// 客戶端  跨域請求 --- 所在位置 http://localhost:80/index.js
$.ajax({
    // 埠號不同,引發跨域
    url: 'http://localhost:3000/user/info',
    type: 'get',
    data: {
        id: 110
    },
    success: function(msg) {
        console.log(msg)
    },
    error: function(err) {
        console.log(err)
    }
})  

// 伺服器端響應 --- 以Node.js為例,伺服器位置http://localhost:3000
var express = require('express');
var router = express.Router();

router.get('/user/info', function(req, res) {
    // 獲取請求的引數
    // req.query.id // 當然這個引數目前是沒有用滴...
    // ... 查詢資料庫中對應的使用者info,假定當前獲取的資料為
    var userInfo = {
        id: 110,
        username: '天王蓋地虎',
        userimg: '/uploads/user/23456.jpg'
    };
    // 響應給客戶端
    res.send(200, userInfo);
})

問題資訊:

當請求按照上面的程式碼進行傳送和響應時,會觸發跨域錯誤,因為二者的埠號是不一致的,沒有遵循同源策略

JSONP跨域請求解決方案:

這裡是重點,重點(敲黑板...),在使用script標籤引入js檔案時是不受同源策略影響的,so我們就可以拿這個做文章了

// 當我們向某個位置傳送請求時,請求和響應要做出如下改變
客戶端請求:
    <script src="http://localhost:3000/user/info?id=110" type="text/javascript"></script>
伺服器端響應:
    var userInfo = {
        id: 110,
        username: '天王蓋地虎',
        userimg: '/uploads/user/23456.jpg'
    };
    
    // 序列化 -- 格式 {"id":110,"username":"天王蓋地虎","userimg":"/uploads/user/23456.jpg"}
    var userInfoJsonStr = JSON. stringify(userInfo);
    
    // 格式 -- 'getInfo({"id":110,"username":"天王蓋地虎","userimg":"/uploads/user/23456.jpg"})'
    res.send(200, 'getInfo('+userInfoJsonStr+')'); 

客戶端接收資料
    // 響應到的資料(瀏覽器 Network自行檢視),該格式下的字串,相當於在呼叫一個名字為 getInfo 的函式,傳遞的引數為 {"id":110,"username":"天王蓋地虎","userimg":"/uploads/user/23456.jpg"}
    // getInfo({"id":110,"username":"天王蓋地虎","userimg":"/uploads/user/23456.jpg"})
    
    在客戶端的JS指令碼中,定義對應的函式 getInfo()
    <script type="text/javascript">
        function getInfo(msg) {
            // 此處的msg就是獲取響應的userInfo
            // 接下來你想幹啥就幹啥
        }
    </script>

以上的這個過程,我們就解決了跨域的問題。

JSONP跨域請求原理

  1. 建立script標籤,將原有的url地址、引數資料設定為src的地址,並附加引數(包括約定的callback函式名)

     var script = document.createElement('script');
     script.src = 'http://localhost:3000/user/info?callback=getInfo&id=110';
     document.body.appendChild(script);
    
  2. 伺服器端響應資料時,要將響應的資料設定為指定的格式 接收的函式名(JSON字串格式資料)

     // 獲取客戶端約定的回撥函式名
     var callback = req.query.callback;
     var userInfo = JSON.stringify({
         id: 110,
         username: '天王蓋地虎',
         userimg: '/uploads/user/23456.jpg'
     });
     res.send(200, callback + '(' + userInfo + ')');
    
  3. 在客戶端定義對應的函式名的函式,該函式的形參就是接收到的伺服器端響應資料

     <script>
         function getInfo(msg) {
             // msg 伺服器端的響應資料
             console.log(msg)
         }
     </script>
    

jQuery封裝的JSONP請求

$.ajax({
    // 請求的url地址
    url: 'http://localhost:3000/user/info',
    // 傳送資料方式
    type: 'get',
    // 引數
    data: {
        id: 110
    },
    // 請求成功時的callback
    success: function(msg) {
        // 你想幹啥就幹啥
    },
    // 預期伺服器返回的資料型別
    dataType: 'jsonp',
    // 指定定義回撥函式名的引數名,若不指定預設引數名為callback
    jsonp: 'callback',
    // 指定回撥函式名,若不指定預設為系統自動生成
    // jsonpCallback: 'getInfo'
})

結語

以上是我整理的關於跨域的原理以及相應的JSONP跨域解決方案,希望能夠給各位小夥伴在工作和學習中提供一定的幫助。 歡迎小夥伴積極留言探討,不要忘記收藏和點贊喜歡呦,還可以進行打賞,請哥喝杯咖啡呀。

相關文章