VUE -- JSONP的誕生、原理及應用實例
問題:
頁面中有一個按鈕,點擊之後會更新網頁中的一個盒子的內容。
Ajax可以很容易的滿足這種無須刷新整個頁面就可以實現數據變換的需求。
但是,Ajax有一個缺點,就是他不允許跨域請求資源。
如果我的代碼在codepen上,我不能將我的數據放到codepen網站上,那麽我只能放到我自己的服務器中,這樣的話,就無法通過Ajax訪問到這個數據了。
解決:
想要實現這種跨域資源請求,有很多解決辦法,列舉出一部分:
- 讓服務器來加載遠程數據,然後在用戶請求時提供給瀏覽器。
- 用<script>或是<iframe>標簽加載外來文件。(因為他們的src屬性允許獲得任何地方的資源。)
- W3C制定的Cross-Origin Resource Sharing(CORS,跨域資源共享)。
- JSONP
JSONP的誕生及原理:
jsonp的原理其實和第二種解決方法一模一樣,只不過他更加方便,然後這種跨域溝通的手段就被賦予了一個名字“JSONP”。
所以首先要弄懂第二種方式是怎麽工作的:
原理:如果一個頁面加載了一個外來的JS文件,瀏覽器就會自動執行這個文件中的代碼。
所以假如localhost想要使用jsonhost上面的一個JSON數據,localhost就可以讓jsonhost來幫他完成這件事情,jsonhost提供給他一個js文件,往要調用的函數中傳入需要的數據,結果是和localhost自己調用函數的效果一模一樣了。
jsonhost:
<script type="text/javascript">
var json=‘["customername1","customername2"]‘;
callbackFunction(json);
</script>
localhost:
<script type="text/javascript">
var json=‘["customername1","customername2"]‘;
callbackFunction(json);
</script>
<script type="text/javascript"> function callbackFunction(result) { var html = ‘<ul>‘; for(var i = 0; i < result.length; i++) { html += ‘<li>‘ + result[i] + ‘</li>‘; } html += ‘</ul>‘; document.getElementById(‘divCustomers‘).innerHTML = html; } </script>
這樣,localhost就已經可以使用jsonhost中的數據了。
然後localhost說,我希望可以在我的用戶點擊一次按扭時,就執行一遍callbackFunction(json),而不是頁面加載後執行一次。
於是他就需要動態的創建<script>標簽:
function callbackFunction(result) { var html = ‘<ul>‘; for(var i = 0; i < result.length; i++) { html += ‘<li>‘ + result[i] + ‘</li>‘; } html += ‘</ul>‘; document.getElementById(‘divCustomers‘).innerHTML = html; } $(".btn").click(function(){ var script = document.createElement(‘script‘); script.setAttribute(‘src‘, "http://jsonhost/json.js"); document.getElementsByTagName(‘header‘)[0].appendChild(script); });
這樣完成之後,效果就和用Ajax異步請求一樣了。
到這裏,故事仿佛就要這樣結束了,但是突然有一天,另一個otherhost跑來和jsonhost說,他想要通過jsoncallbackFunction處理json,jsonhost就很為難,於是他們聚在一起,想要找到一個辦法,可以不需要全部使用同一個函數名,也可以獲取同一個數據。
最終他們想到了一個完美的辦法——jsonhost用的函數名用一個變量代替,localhost和otherhost請求數據的時候,傳入這個變量名,這樣就可以各自決定各自使用的函數名了。
jsonhost:
<?php header(‘Content-type: application/json‘); //告訴接收數據的對象此頁面輸出的是json數據 $json = ‘["customername1","customername2"]‘; echo $_GET[‘callback‘] . "(" . $json . ")"; ?>
localhost:
<script type="text/javascript"> function getJson(url,funName){ var script = document.createElement(‘script‘); script.setAttribute(‘src‘, url+funName); document.getElementsByTagName(‘head‘)[0].appendChild(script); } function callbackFunction(result) { var html = ‘<ul>‘; for(var i = 0; i < result.length; i++) { html += ‘<li>‘ + result[i] + ‘</li>‘; } html += ‘</ul>‘; document.getElementById(‘divCustomers‘).innerHTML = html; } $(".btn").click(function(){ getJson("http://jsonhost/jsonp.php?jsoncallback=","callbackFunction"); }); </script>
otherhost:
<script type="text/javascript"> function getJson(url,funName){ var script = document.createElement(‘script‘); script.setAttribute(‘src‘, url+funName); document.getElementsByTagName(‘head‘)[0].appendChild(script); } function jsoncallbackFunction(result) { console.log(result); } $(".btn").click(function(){ getJson("http://jsonhost/jsonp.php?jsoncallback=","jsoncallbackFunction"); }); </script>
這樣一來,使用什麽函數名都是不同host自己的事情,他們互不幹擾,jsonhost也不用操心這件事,專心提供數據就可以了。其他host也紛紛前來獲取json。於是這種模式被廣泛使用,然後這種通信方式就被命名為“JSONP”。
如果用jQuery的話,就不用自己命名函數並傳遞給參數了,因為這個函數名一點也不重要,他只是個代號而已,jQuery會幫我們自動生成一個函數名,然後將得到的數據傳給這個函數。jQuery還會幫我們創建script標簽, 我們只要關心如何處理這個數據就好了。
<script src="http://apps.bdimg.com/libs/jquery/1.8.3/jquery.js"></script> <script> $.getJSON("http://jsonhost/jsonp.php?jsoncallback=?", function(data) { var html = ‘<ul>‘; for(var i = 0; i < data.length; i++) { html += ‘<li>‘ + data[i] + ‘</li>‘; } html += ‘</ul>‘; $(‘#divCustomers‘).html(html); }); </script>
jQuery把JSONP封裝到Ajax裏面,但本質上這兩種技術是完全不同的。
JSONP的原理是,當前網頁動態執行異域返回的js代碼,這個代碼是個執行請求數據的函數。瀏覽器執行這個函數,效果和當前域獲得數據執行函數是一樣的。
應用實例:
知道了原理之後,迫不及待的想要用一下JSONP來獲取數據。這裏用PHP來實現。
首先,需要有個服務器,如果沒有服務器的話,可以使用wampserver軟件模擬一個,這個軟件還會建立一個集成環境,可以運行PHP文件。點擊查看wampserver教程
有了自己的服務器和PHP運行環境之後,就可以開始了。想要在codepen上獲取本地數據。
本機PHP:
<?php header(‘Content-type: application/json‘); //告訴接收數據的對象此頁面輸出的是json數據 $quotes = ‘[{ "quote": "If you can\‘t get rid of the skeleton in your closet, you\‘d best teach it to dance.", "author": "George Bernard Shaw" }, { "quote": "We\‘ll always have Paris.", "author": "Casablanca" }, { "quote": "A mathematician is a device for turning coffee into theorems.", "author": "Paul Erdos" }, { "quote": "Do, or do not. There is no \‘try\‘.", "author": "Star Wars: Empire Strikes Back" }, { "quote": "Some cause happiness wherever they go; others, whenever they go.", "author": "Oscar Wilde" }, { "quote": "Problems worthy of attack prove their worth by fighting back.", "author": "Paul Erdos" }, { "quote": "Maybe this world is another planet\‘s Hell.", "author": "Aldous Huxley" }]‘; echo $_GET[‘callback‘] . "(" . $quotes . ")"; ?>
codepen上的js:
function update(){ var index=Math.floor(Math.random()*11); $.getJSON("http://localhost/quotes.php?callback=?",function(data){ var num=Math.floor(Math.random()*6); $(".wrap").fadeOut(600,function(){ $(".quo").html(data[num].quote); $(".auth").html(data[num].author); $("body, .quote-box button").css("background-color",colors[index]); $(".wrap").css("color",colors[index]); }).fadeIn(600); }); } $(document).ready(function(){ update(); $(".update").click(update); });
點擊查看在線demo,必須將本機模擬成服務器並建立PHP環境並添加了PHP文件才能運行。
而且要註意把codepen的https改成http。
成功之後可以看到,發送的請求中,傳給callback的是一個jQuery自動生成的函數:
返回的也是這個函數調用數據:
如果不想自己配置的話,可以應用其他網站提供的API,實現原理是一樣的。demo
參考:
- JSONP 教程
- 《jQuery基礎教程》
- 說說JSON和JSONP,也許你會豁然開朗,含jQuery用例
VUE -- JSONP的誕生、原理及應用實例