序 1. 同源策略 是瀏覽器處於安全考慮,為通信設置了“相同的域、相同的埠、相同的協議”這一限制。這讓我們的ajax請求存在跨域無許可權訪問的問題。 2. 同時我們發現script標簽引入腳本的行為並不受同源策略的限制,但是script引入的文件會被立即執行,如果其內容不符合js語法,則會報錯; 操 ...
序
同源策略是瀏覽器處於安全考慮,為通信設置了“相同的域、相同的埠、相同的協議”這一限制。這讓我們的ajax請求存在跨域無許可權訪問的問題。
同時我們發現script標簽引入腳本的行為並不受同源策略的限制,但是script引入的文件會被立即執行,如果其內容不符合js語法,則會報錯;
操作原理
針對以上情況,誕生了jsonp:
利用script標簽的src屬性來請求介面,並向介面傳遞一個回調函數(剋服了同源問題)
介面將數據以
回調函數參數
的形式同回調函數一同傳回;此時傳回則是這樣形式的一個字元串:回調函數名(數據)
,這樣就符合js語法了(剋服了script標簽引入內容非js報錯的問題)
實例操作
紙上得來總覺淺,絕知此事要躬行。jsonp的原理我早就倒背入流了,但是看著覺得明白,但總覺得少了點什麼沒抓住。所以,實際操刀試試吧。點擊下載源碼
下載代碼後,進入some-code/jsonp-demo文件夾,該文件夾的目錄為:
app.js
package.json
views
命令行進入當前目錄,安裝包依賴:
npm install
安裝完畢後,運行程式:
node app.js
如果看到命令行輸出“app is listening”則表示運行成功
修改host
因為需要模擬跨域,所以在host文件中創建倆個不同的功能變數名稱,在host文件中添加以下內容:
127.0.0.1 www.a.com www.b.com
自此結束,在瀏覽器中輸入http://www.a.com:3000/,如果訪問成功則表示大功告成,頁面中應該出現倆個按鈕。
這個時候,我們打開瀏覽器的控制台,分別點擊頁面中的倆個按鈕,就可以看到測試結果啦。
代碼分析
入口文件:app.js
設定模版引擎
app.set('views', path.join(__dirname, 'views')); var swig = new swig.Swig(); app.engine('html', swig.renderFile); app.set('view engine', 'html');
設置路由和介面
訪問www.a.com時,渲染view/index.html頁面
app.get("/",function(req,res){ res.render('index', {}); })
請求www.b.com/index.json時,返回數據,這裡伺服器收到jsonp的回調函數名,並把它與數據拼接在一起返回給客戶端
//模擬數據 var data = {"brand":23} app.get("/index.json",function(req,res){ //解析請求路徑 var param = urlLib.parse(req.url,true); var returnValue = param.query.callback+ '(' + JSON.stringify(data) +')'; res.send(returnValue) })
啟動服務
app.listen(3000,function(){ console.log("app is listening") })
頁面:view/index.html
頁面中有倆個按鈕:
jsonp_button
和ajax_button
,點擊以後分別進行jsonp請求和ajax請求。綁定點擊事件
jsonp_button.onclick = function(){ var url = "http://www.b.com:3000/index.json?callback=jsonp"; //向頁面中添加script標簽,進行jsonp請求 creatScript(url) } ajax_button.onclick = function(){ //ajax請求 var xhr = getXhr(); xhr.open("get","http://www.b.com:3000/index.json"); xhr.send(); if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); } else { console.log("Request was unsuccessful: " + xhr.status); } } function getXhr(){ var xhr; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest() }else{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; }
動態創建script標簽
function creatScript(url){ var scriptTag = document.createElement('script'); scriptTag.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(scriptTag); }
jsonp回調函數
function jsonp(data) { //獲取數據 console.log(data); }
由上面可以得出:jsonp中所有請求數據的後續操作應寫在jsonp的回調函數中,它類似於ajax 的 success操作。
最後一句話概括jsonp:jsonp就是原本應該發送json數據給客戶端的伺服器,不再發送json,改為發送一段調用回調函數的js代碼,而原本應該返回的數據則是該函數的參數。