Stories

Detail Return Return

jsonp跨域原理解析 - Stories Detail

1、背景:

由於瀏覽器同源策略的限制,非同源下的請求,都會產生跨域問題,jsonp即是為了解決這個問題出現的一種簡便解決方案。

2、同源策略:

同一協議,同一域名,同一端口號。當其中一個不滿足時,我們的請求即會發生跨域問題。

舉個栗子🌰:

http://www.abc.com:3000到https://www.abc.com:3000的請求會出現跨域(域名、端口相同但協議不同)
http://www.abc.com:3000到http://www.abc.com:3001的請求會出現跨域(域名、協議相同但端口不同)
http://www.abc.com:3000到http://www.def.com:3000的請求會出現跨域(域名不同)

3、突破同源策略限制:


現在知道了同源策略,那我們就來看下jsonp是如何突破同源策略的限制實現跨域的

首先,不知道大家有沒有注意,不管是我們的script標籤的src還是img標籤的src,或者説link標籤的href他們沒有被同源策略所限制,比如我們有可能使用一個網絡上的圖片,就可以請求得到,jsonp即是利用這一特性實現的(這也就是為什麼jsop只支持get請求的原因)。

<img src="https://ss3.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=6d0bf83bda00baa1a52c41bb7711b9b1/0b55b319ebc4b745b19f82c1c4fc1e178b8215d9.jpg">

src或href鏈接的靜態資源,本質上來説也是一個get請求,拿csdn上的靜態資源舉例:
20180901175901119.png

可以看到,確實是個get請求無疑。同理img標籤的src和link標籤的href也會發送一個get請求去請求靜態資源。那麼我們通過這點,是不是發現了點什麼,這些標籤的src和link屬性,並沒有受同源策略的限制。説到這裏jsonp的實現原理就浮出水面了。

jsonp就是使用通源策略這一“漏洞”,實現的跨域請求(這也是jsonp跨域只能用get請求的原因所在)。想象一下,既然是個get請求,那麼服務端一定可以接收到,並做出反饋。ok,知道這兩點之後,我們開始具體使用jsonp進行跨域請求。

4、JSONP跨域實現:


根據上邊所説的,我們要用過利用img、srcipt,link標籤的src或href屬性(到底使用那個標籤無所謂)來實現,那麼我們如何做呢,我們來看一段簡單的代碼,為了方便,我這裏使用jQuery:

$('#btn').click(function(){
    var frame = document.createElement('script');
    frame.src = 'http://localhost:3000/article-list?name=leo&age=30&callback=func';
    $('body').append(frame);
});

可以看到,讓我們點擊按鈕的時候,創建了一個script標籤(即會發送一個get請求到src指向的地址),src地址是"localhost:3000/article-list",這個src地址,就是我們請求的服務端接口。注意,這裏我們有是那個參數,name,age和callback,name和age不説了,這跟我們平時普通的get請求參數無異。主要説下callback這個參數,callback參數就是核心所在。為什麼要定義callback呢?首先我們知道,這個get請求已經被髮出去了,那麼我們如何接口請求回來的數據呢,callback=func則可以幫我們做這件事。我們繼續看下邊的代碼。

<button id="btn">點擊</button>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  <script>
    $('#btn').click(function(){
        var frame = document.createElement('script');
        frame.src = 'http://localhost:3000/article-list?name=leo&age=30&callback=func';
        $('body').append(frame);
    });

    function func(res){
        alert(res.message+res.name+'你已經'+res.age+'歲了');
    }
  </script>

我們聲明瞭一個func函數,但沒有執行,你可以想一下,如果服務端接口到get請求,返回的是func({message:'hello'}),這樣的話在服務端不就可以把數據通過函數執行傳參的方式實現數據傳遞了嗎。

4、服務端代碼實現:


服務端代碼,這裏使用的是express,這裏不再對express做具體介紹。代碼如下:

router.get('/article-list', (req, res) => {
  console.log(req.query, '123');
  let data = {
    message: 'success!',
    name: req.query.name,
    age: req.query.age
  }
  data = JSON.stringify(data)
  res.end('func(' + data + ')');
});

ok,接下來當我們點擊提交的時候,就獲取到了服務端反回的數據,這樣下來,就完成了實現jsonp的跨域,如下結果:
20180901192227415.png

總結:


需要注意的是,callback參數定義的方法是需要前後端定義好的,具體什麼名字,商討好就可以了。其實jsonp的整個過程就類似於前端聲明好一個函數,後端返回執行函數。執行函數參數中攜帶所需的數據,整個過程實際非常簡單易懂。

Add a new Comments

Some HTML is okay.