摘要:因?yàn)橛型床呗?,而在?shí)際開(kāi)發(fā)中又常常會(huì)有跨域的需求,早期開(kāi)發(fā)者為了解決跨域問(wèn)題而搞出來(lái)這樣一個(gè)頗為奇怪的東西。安全早期的瀏覽器處于安全層面的考量,制定同源策略,限制了一個(gè)源中加載文本或腳本與來(lái)自其它源中資源的交互方式。
AJAX、JSON、JSONP
在 WEB 開(kāi)發(fā)中,經(jīng)常見(jiàn)到諸如 AJAX、JSON、JSONP 這些名詞。三者看起來(lái)很像,很多同學(xué)尤其是沒(méi)有系統(tǒng)了解過(guò)前端技術(shù)體系的同學(xué),平常只是借助類似 JQuery 這類庫(kù)封裝好的函數(shù)使用而已,并不了解其原理。但這三種東西具體是什么,有什么關(guān)系和區(qū)別卻常常說(shuō)不清楚。
接下來(lái),會(huì)簡(jiǎn)要介紹一下三者的的含義,重點(diǎn)闡述 JSONP 的來(lái)源和原理,以及為什么 JSONP 不是 AJAX。
AJAX (Asynchronous JavaScript + XML)Ajax isn’t a technology. It’s really several technologies, each flourishing in its own right, coming together in powerful new ways. Ajax incorporates:
standards-based presentation using XHTML and CSS;
dynamic display and interaction using the Document Object Model;
data interchange and manipulation using XML and XSLT;
asynchronous data retrieval using XMLHttpRequest;
and JavaScript binding everything together.
異步 JavaScript + XML,是在 2005 年由 Jesse James Garrett 提出的一個(gè)術(shù)語(yǔ)。 AJAX 并非特指某種技術(shù), 描述的是一種結(jié)合使用大量已有技術(shù)的方式, 包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 還有最重要的 XMLHttpRequest 對(duì)象.
盡管在 AJAX 中 X 代表 XML, 但現(xiàn)在更多的在使用 JSON,因?yàn)?JSON 具有很多優(yōu)勢(shì),比如更輕量并且是 JavaScript 的一部分。在 AJAX 模型中 JSON 和 XML 都用于承載信息.
JSON(Javascript Object Notation)JSON 是一種輕量級(jí)的數(shù)據(jù)交換格式。由道格拉斯·克羅克福特(Douglas Crockford)在 2012 年發(fā)明,并逐漸取代 XML 成為事實(shí)上的數(shù)據(jù)交換格式標(biāo)準(zhǔn)。
JSON 基于 JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一個(gè)子集。但采用完全獨(dú)立于語(yǔ)言的文本格式,并使用了類似于 C 語(yǔ)言家族的習(xí)慣。
在 JSON 中,一共 6 種數(shù)據(jù)類型:
number:跟 Javascript 的數(shù)值一致,除去未曾使用的八進(jìn)制與十六進(jìn)制格式,和一些編碼細(xì)節(jié)
boolean:true 和 false
string:是由雙引號(hào)包圍的任意數(shù)量Unicode字符的集合,使用反斜線轉(zhuǎn)義
null:null
array:數(shù)組是值(value)的有序集合。一個(gè)數(shù)組以“[”(左中括號(hào))開(kāi)始,“]”(右中括號(hào))結(jié)束,值之間使用“,”(逗號(hào))分隔
object:對(duì)象是一個(gè)無(wú)序的“‘名稱/值’對(duì)”集合。一個(gè)對(duì)象以“{”(左括號(hào))開(kāi)始,“}”(右括號(hào))結(jié)束,每個(gè)“名稱”后跟一個(gè)“:”(冒號(hào));“‘名稱/值’ 對(duì)”之間使用“,”(逗號(hào))分隔
以及上面的任意組合。
在 JavaScript 中有一個(gè)全局對(duì)象 JSON,包含兩個(gè)方法 JSON.stringify() 和 JSON.parse(),用于序列化和解析 JSON。
當(dāng)然也有人使用 eval("(" + string + ")") 代替 JSON.parse() 來(lái) 解析JSON,相比而言這種方式的容錯(cuò)性更高。
JSONP(JSON with Padding)因?yàn)?XMLHttpRequest 有同源策略,而在實(shí)際開(kāi)發(fā)中又常常會(huì)有跨域的需求,早期開(kāi)發(fā)者為了解決跨域問(wèn)題而搞出來(lái)這樣一個(gè)頗為奇怪的東西。產(chǎn)生原因和名字一樣古怪,光聽(tīng)名字恐怕沒(méi)幾個(gè)人知道說(shuō)的是個(gè)什么東西。
剛好 標(biāo)簽可以引用其他域下的靜態(tài)資源,想想我們有時(shí)候在站點(diǎn)引入的數(shù)據(jù)統(tǒng)計(jì)類的 JS。
但我們要的是數(shù)據(jù),而不是一段靜態(tài)的 JS 代碼,怎么辦?
這還不簡(jiǎn)單嗎,讓服務(wù)器動(dòng)態(tài)生成 js ,再把數(shù)據(jù)放進(jìn)去不就可以嗎。為了區(qū)分每一份數(shù)據(jù),還需要針對(duì)返回的數(shù)據(jù)做一個(gè)標(biāo)識(shí),其實(shí)就是在數(shù)據(jù)外面包裹一個(gè)函數(shù)名。
然后需要瀏覽器端預(yù)先設(shè)置好這樣一個(gè)函數(shù),返回的數(shù)據(jù)就相當(dāng)于一次執(zhí)行過(guò)程,對(duì)獲取數(shù)據(jù)的處理。
總結(jié)AJAX 是一類技術(shù)的集合,其中最重要的是 XMLHttpRequest
JSON 是一個(gè)數(shù)據(jù)交換格式,也是目前事實(shí)上的標(biāo)準(zhǔn)
JSONP 是為解決跨域問(wèn)題搞出來(lái)的一種獲取數(shù)據(jù)的方式
舉個(gè)栗子接下來(lái),用這個(gè)簡(jiǎn)單的示例來(lái)說(shuō)明如何通過(guò) JSONP 的方式獲取數(shù)據(jù),以及它到底是怎樣工作的。
服務(wù)器這里使用 Node.js 返回一段簡(jiǎn)單的數(shù)據(jù)。
/** * 一個(gè)簡(jiǎn)單的 http 服務(wù)器,返回 json 數(shù)據(jù) * 跟 Node 主頁(yè)上的那個(gè)經(jīng)典例子沒(méi)太大差別 */ var http = require("http"); var urllib = require("url"); var host = "127.0.0.1"; var port = 9999; var data = {"name": "Mirreal", "age": "24"}; http.createServer(function(req, res) { var params = urllib.parse(req.url, true); if (params.query && params.query.callback) { var str = params.query.callback + "(" + JSON.stringify(data) + ")"; // jsonp res.writeHead(200, { "Content-Type": "application/javascript" }); res.end(str); } else { res.end(JSON.stringify(data)); // 普通的json } }).listen(port, host, function() { console.log("server is listening on port " + port); });瀏覽器
// zepto 的寫法 $.ajax({ type: "GET", url: "http://127.0.0.1:9999", data: { _input_charset: "utf-8" }, dataType: "jsonp", timeout: 300, context: $("body"), success: function(data){ console.log(data) }, error: function(xhr, type) { console.log("Ajax error!") } });
這樣就很輕松的通過(guò) JSONP 的方式獲取到數(shù)據(jù),我們似乎也不需要關(guān)心里面究竟是怎么一回事。但有時(shí)候肯能會(huì)有人問(wèn)起:“為什么 jsonp 不能使用 POST 方法”的問(wèn)題,其實(shí)稍微了解一下 JSONP 的原理,這種問(wèn)題完全就不存在了。
雖然像 JQuery 這類庫(kù)將 JSONP 封裝到 $.Ajax() 上,但準(zhǔn)確來(lái)講是不對(duì)的。因?yàn)?JSONP 只是通過(guò)動(dòng)態(tài)地通過(guò) 標(biāo)簽去請(qǐng)求一段 JS 代碼(或者叫數(shù)據(jù)),而非使用 XMLHttpRequest ,原理就像下面這樣:
對(duì) JSONP 的簡(jiǎn)單封裝/** * 對(duì) JSONP 的一種簡(jiǎn)單封裝 * * @param {Object} options * @returns null */ function getJsonp(options) { var callbackName = options.callbackName; var url = options.url; var scriptElem = document.createElement("script"); scriptElem.setAttribute("src", url + "?callback=" + callbackName); scriptElem.onload = function(e) { delete window[callbackName]; this.parentNode.removeChild(this); }; scriptElem.onerror = function(e) { console.log(e, "load error"); delete window[callbackName]; this.parentNode.removeChild(this); }; window[callbackName] = options.success; // 調(diào)用 document.querySelector("head").appendChild(scriptElem); }
這段代碼對(duì) JSONP 進(jìn)行一層簡(jiǎn)單包裝,調(diào)用也很簡(jiǎn)單:
getJsonp({ "url": "http://127.0.0.1:9999/", "callbackName": "log", "success": function(data) { console.log("我是回調(diào)函數(shù),我拿到數(shù)據(jù)了", data); } });
看上去代碼還挺長(zhǎng)的,實(shí)際上核心代碼不多,分三步:
1.創(chuàng)建一個(gè) 標(biāo)簽,并設(shè)置其 urlvar scriptElem = document.createElement("script"); scriptElem.setAttribute("src", url + "?callback=" + callbackName);2.設(shè)置回調(diào)函數(shù)
window[callbackName] = options.success;
這里簡(jiǎn)單處理,直接把傳入的回調(diào)函數(shù)設(shè)置成全局的
3.調(diào)用document.querySelector("head").appendChild(scriptElem);
實(shí)際上就是把 加到 html 文檔中,這樣就會(huì)去加載標(biāo)簽的內(nèi)容,也就是一個(gè) JS 文件。
但通?,F(xiàn)實(shí)中跑的代碼內(nèi)容會(huì)更多,包含一些錯(cuò)誤控制、參數(shù)拼接、超時(shí)處理、性能安全等方面的,但它仍然清楚地描述 JSONP 的原理。
安全早期的瀏覽器處于安全層面的考量,制定同源策略,限制了一個(gè)源(origin)中加載文本或腳本與來(lái)自其它源(origin)中資源的交互方式。
但是隨著互聯(lián)網(wǎng)的發(fā)展催生了跨域訪問(wèn)進(jìn)行數(shù)據(jù)交互的需求,于是 JSONP 就產(chǎn)生了,以及后來(lái)的 CORS 機(jī)制,允許 XMLHttpRequest 對(duì)象發(fā)起跨域的請(qǐng)求。
但是另一方面,也增加了安全風(fēng)險(xiǎn),我們?cè)谑褂玫臅r(shí)候應(yīng)當(dāng)更加謹(jǐn)慎小心,防止 XSS、CSRF 等攻擊。
其他 數(shù)據(jù)預(yù)覽之前碰到一個(gè)問(wèn)題,在調(diào)用一些接口返回的數(shù)據(jù)無(wú)法使用 Chrome 預(yù)覽,自己寫測(cè)試接口的時(shí)候也碰到過(guò)。后來(lái)發(fā)現(xiàn),只是因?yàn)闆](méi)有在 response 頭部加上 Content-Type: application/javascript,僅此而已。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87744.html
摘要:前言最近因?yàn)楣ぷ鞯木壒?,幾乎把市面上所有?kù)都下載了一遍,卻發(fā)現(xiàn)沒(méi)有百分百讓我滿意的,最后自己手動(dòng)改寫了,才符合了要求,也因此有了這篇文章。在這一點(diǎn)上不得不說(shuō)做的很好,的函數(shù)包含了對(duì)各種情況的處理,還偽造了一個(gè)狀態(tài)碼的返回。 前言 最近因?yàn)楣ぷ鞯木壒?,幾乎把市面上所有Jsonp庫(kù)都下載了一遍,卻發(fā)現(xiàn)沒(méi)有百分百讓我滿意的,最后自己手動(dòng)改寫了Jsonp,才符合了要求,也因此有了這篇文章。本文...
摘要:因?yàn)橥床呗缘南拗疲覀儾荒茉谂c外部服務(wù)器進(jìn)行通信的時(shí)候使用。這個(gè)是跨域服務(wù)器取數(shù)據(jù)的接口,參數(shù)為回調(diào)函數(shù)的名字,返回的格式為原理首先在客戶端注冊(cè)一個(gè)然后把的名字傳給服務(wù)器。 一、同源策略 同源策略,它是由Netscape提出的一個(gè)著名的安全策略,現(xiàn)在所有的可支持javascript的瀏覽器都會(huì)使用這個(gè)策略。 為什么需要同源策略,這里舉個(gè)例子: 假設(shè)現(xiàn)在沒(méi)有同源策略,會(huì)發(fā)生什么事...
摘要:運(yùn)行一下頁(yè)面,成功彈出提示窗口,的執(zhí)行全過(guò)程順利完成到這里為止的話,相信你已經(jīng)能夠理解的客戶端實(shí)現(xiàn)原理了吧剩下的就是如何把代碼封裝一下,以便于與用戶界面交互,從而實(shí)現(xiàn)多次和重復(fù)調(diào)用。 先說(shuō)說(shuō)JSONP是怎么產(chǎn)生的: 其實(shí)網(wǎng)上關(guān)于JSONP的講解有很多,但卻千篇一律,而且云里霧里,對(duì)于很多剛接觸的人來(lái)講理解起來(lái)有些困難,小可不才,試著用自己的方式來(lái)闡釋一下這個(gè)問(wèn)題,看看是否有幫助。 1、...
摘要:是什么說(shuō)實(shí)話,我學(xué)了這么久,其實(shí)也沒(méi)有好好了解這個(gè)東西,當(dāng)然平常自己在前端方面也涉獵較淺。是什么是的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問(wèn)的問(wèn)題。有效避免了直接向遠(yuǎn)程服務(wù)器請(qǐng)求數(shù)據(jù) JSONP 是什么 說(shuō)實(shí)話,我學(xué)了這么久,其實(shí)也沒(méi)有好好了解這個(gè)東西,當(dāng)然平常自己在前端方面也涉獵較淺。 1) jsonp 是什么 JSONP(JSON with Padding)是JSON的一...
摘要:是什么說(shuō)實(shí)話,我學(xué)了這么久,其實(shí)也沒(méi)有好好了解這個(gè)東西,當(dāng)然平常自己在前端方面也涉獵較淺。是什么是的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問(wèn)的問(wèn)題。有效避免了直接向遠(yuǎn)程服務(wù)器請(qǐng)求數(shù)據(jù) JSONP 是什么 說(shuō)實(shí)話,我學(xué)了這么久,其實(shí)也沒(méi)有好好了解這個(gè)東西,當(dāng)然平常自己在前端方面也涉獵較淺。 1) jsonp 是什么 JSONP(JSON with Padding)是JSON的一...
閱讀 975·2023-04-26 02:49
閱讀 1187·2021-11-25 09:43
閱讀 2558·2021-11-18 10:02
閱讀 2933·2021-10-18 13:32
閱讀 1294·2019-08-30 13:54
閱讀 2092·2019-08-30 12:58
閱讀 3024·2019-08-29 14:06
閱讀 2166·2019-08-28 18:10