嘛是jsonp
一個眾所周知的問題,Ajax請求是不能跨域的,甭管你是靜態頁面、動態網頁、web服務、WCF,只要是跨域請求,一律不准。
不過我們又發現,Web頁面上調用js文件時則不受是否跨域的影響(不僅如此,我們還發現凡是擁有src這個屬性的標簽都擁有跨域的能力,比如<script>、<img>、<iframe>)。
於是如果想通過純web端跨域訪問數據就可以這樣:在遠程服務器上設法把數據裝進js格式的文件里,供客戶端調用和進一步處理。
恰巧有一種叫做JSON的純字符數據格式可以簡潔的描述復雜數據,更妙的是JSON還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數據。
這樣子解決方案就呼之欲出了,web客戶端通過與調用腳本一模一樣的方式,來調用跨域服務器上動態生成的js格式文件,顯而易見,服務器之所以要動態生成JSON文件,目的就在於把客戶端需要的數據裝入進去。
客戶端在對js文件調用成功之后,也就獲得了自己所需的數據,剩下的就是按照自己需求進行處理和展現了。
為了便於客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作JSONP,該協議的一個要點就是允許用戶傳遞一個callback參數給服務端,然后服務端返回數據時會將這個callback參數作為函數名來包裹住JSON數據,這樣客戶端就可以隨意定制自己的函數來自動處理返回數據了。
JSONP的客戶端實現
First Blood
假設遠程服務器有個app.js文件,代碼如下
alert('111111');
html頁面如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="http://xx.xx.xx.xx/app.js"></script> </head> <body> </body> </html>
很顯然頁面會顯示一個彈出框
Double Kill
現在稍微改動一下
<!-- html代碼 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> var handler = function (data) { alert(data) } </script> <script src="http://xx.xx.xx.xx/app.js"></script> </head> <body> </body> </html>
// 遠程服務器的 app.js 代碼 handler({"result":"我是遠程js帶來的數據"});
毫無疑問,是可以運行成功的
Triple Kill
動態生成handler函數名
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> var xxxHandler = function(data){ alert(data); }; // 提供jsonp服務的url地址(不管是什么類型的地址,最終生成的返回值都是一段JavaScript代碼) var url = "http://xx.xx.xx.xx/xyz?param1=123&callback=xxxHandler"; // 創建script標簽,設置其屬性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script標簽加入head,此時調用開始 document.body.appendChild(script); </script> </head> <body> </body> </html>
這次改動,不再把遠程js文件寫死。在調用的url中傳遞了一個code參數,告訴服務器參數信息,而callback參數則告訴服務器,本地回調函數叫做xxxHandler,所以請把查詢結果傳入這個函數中進行調用。
廣州vi設計公司 http://www.maiqicn.com 我的007辦公資源網 https://www.wode007.com
Ultra Kill
不廢話了,直接上最后封裝過的代碼
(function (global) { function jsonp (url, params, callback) { let queryStringArr = []; for (var k in params) { queryStringArr.push(`${k}=${param[k]}`); } let random = Math.random().toString().replace('.', ''); let callbackFunctionName = 'jsonp_' + random; queryStringArr.push(`callback=${callbackFunctionName}`); let script = document.createElement('script'); script.src = url + '?' + queryStringArr.join('&'); document.body.appendChild(script); global[callbackFunctionName] = function (param) { callback(param); document.body.removeChild(script); }; } global.jsonp = jsonp; })(window);