天天看點

跨域-JSONP

由于同源政策的限制,

Ajax

不允許跨域通路,但是像

<script>

<link>

<img>

<iframe>

這些标簽是允許跨域的,但你并不能修改這些資源,比如

iframe

裡的内容,更準确的來說這些标簽可以擷取資源。

JSONP

JSON with padding

(填充式

JSON

)。

JSONP

利用了

HTML

<script>

标簽可以跨域的原理,利用

<script>

标簽向伺服器請求一段js代碼,然後執行這一段JS代碼,實作跨域。

首先,要了解

<script>

标簽上發生了什麼。在編碼中我們經常會通過

<script>

引用cdn等處于其它域名下的靜态資源,毫無疑問是可以加載成功的。其實

<script>

标簽的實質就是往

<script>

标簽裡的src發起一個請求,擷取到JS代碼,然後把代碼放到目前執行。實際上裡面的.js字尾隻是我們習慣的用法,無論是什麼檔案,都會把裡面的内容下載下傳下來當作JS在目前來執行。是以,即使請求對的是

.txt

檔案,也會把

.txt

裡面的内容下載下傳下來當作JS在目前來執行。是以,無論

<script>

标簽裡可以是任何東西,隻要是可以通路到并且得到資料的一個接口就可以了,都會把傳回的内容當作JS在目前運作。

下面我們來了解以下Ajax是怎麼利用

<script>

标簽來進行跨域通路的。

首先要說一下,

JSONP

是需要前後端的配合的,很多人之是以對對

JSONP

懵懵懂懂,從我自身的感覺來說,很多是因為不了解後端是怎麼與前端配合實作

JSONP

的。

前端代碼:

**HTML**

    <button class="getData">擷取資料</button>

**JavaScript**

  var btn=document.getElementById("#getData");
  btn.addEventListener('click', function(){
    var script = document.createElement('script');
    script.src = 'http://www.wuxiaozhou.com/getData?callback=getData';
    document.head.appendChild(script);
    document.head.removeChild(script);
  })
  function getData(data){
    document.write(data);
  }
           

後端代碼(後端語言有很多種,可能不同語言的代碼會不一樣):

app.get('/getData', function(req, res){
    var data = ["海賊王","火影忍者","灌籃高手","名偵探柯南"];
    var cb = req.query.callback;
    if(cb){
        res.send(cb + '('+ JSON.stringify(data) + ')');
    }else{
        res.send(data);
    }   
})
           

前端代碼裡,比如代碼頁面所在的域名是

http://www.xiaozhou.com

我給個按鈕綁定了一個事件,點選按鈕會向為

http://www.wuxiaozhou.com/getData

擷取資料。因為兩者的主機名不一樣,是以這個是跨域通路。

其實是先建立一個

<script>

标簽,然後把

<script>

标簽的src屬性設定為擷取資料的接口加一個鍵值對

http://www.wuxiaozhou.com/getData?callback=getData

,再把

<script>

标簽放到頁碼的

<head>

标簽裡面。當點選了按鈕後,上面的操作就會進行,就會向

http://www.wuxiaozhou.com/getData

發起請求。

也許你會有疑問,為什麼需要在請求的接口後面加上一個鍵值對?下面就為你解答。

後端接收到請求後,找到

callback

的值,然後把

callback

的值加上用括号括起來并轉化成字元串的需要傳回的資料傳回來。在我的這個例子中,

callback

的值就是

getData

,傳回給用戶端的就是

getData('["海賊王","火影忍者","灌籃高手","名偵探柯南"]')

可能你也注意到後端語言裡有一個判斷,如果判斷到有

callback

的值存在,那就說明是一個跨域的請求,是按照上面我們說的方式發起的,用

if

後面的方式傳回資料;因為同域請求的話請求裡是沒有後面的那一個鍵值對的,是以背景判斷沒有這個

callback

的值,就會将資料直接傳回,也就是

else

後面的方式。這裡是為了同時可以處理同源請求和跨域的

JSONP

請求。

前端頁面接收到後端傳回對的資料後,就會将傳回的資料當作JS去執行,在我們這個例子中就是:

你也注意到我們在前端代碼裡聲明了一個與

callback

的值一樣的函數,在我們這個例子就是:

function getData(data){
    document.write(data);
  }
           

是以就會執行這個函數,參數是

'["海賊王","火影忍者","灌籃高手","名偵探柯南"]'

。這個時侯相當于資料被當作參數傳進了這個函數了,這個函數就是資料的處理函數,你也可以對傳回的字元串資料進行其它的各種各樣的操作。在我的這個例子中就會把

'["海賊王","火影忍者","灌籃高手","名偵探柯南"]'

顯示在頁面上。

前端跟後端要協調好的就是在發送請求的參數名要一緻,比如我這個例子的參數名是

callback

,後端要查詢的參數名也要是

callback

,否則的話後端就找不到前端發送的參數。沒有特殊說明,一般約定俗成都是

callback

吧。

繼續閱讀