摘要:因為有同源策略,而在實際開發(fā)中又常常會有跨域的需求,早期開發(fā)者為了解決跨域問題而搞出來這樣一個頗為奇怪的東西。安全早期的瀏覽器處于安全層面的考量,制定同源策略,限制了一個源中加載文本或腳本與來自其它源中資源的交互方式。
AJAX、JSON、JSONP
在 WEB 開發(fā)中,經(jīng)常見到諸如 AJAX、JSON、JSONP 這些名詞。三者看起來很像,很多同學尤其是沒有系統(tǒng)了解過前端技術(shù)體系的同學,平常只是借助類似 JQuery 這類庫封裝好的函數(shù)使用而已,并不了解其原理。但這三種東西具體是什么,有什么關系和區(qū)別卻常常說不清楚。
接下來,會簡要介紹一下三者的的含義,重點闡述 JSONP 的來源和原理,以及為什么 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 提出的一個術(shù)語。 AJAX 并非特指某種技術(shù), 描述的是一種結(jié)合使用大量已有技術(shù)的方式, 包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 還有最重要的 XMLHttpRequest 對象.
盡管在 AJAX 中 X 代表 XML, 但現(xiàn)在更多的在使用 JSON,因為 JSON 具有很多優(yōu)勢,比如更輕量并且是 JavaScript 的一部分。在 AJAX 模型中 JSON 和 XML 都用于承載信息.
JSON(Javascript Object Notation)JSON 是一種輕量級的數(shù)據(jù)交換格式。由道格拉斯·克羅克福特(Douglas Crockford)在 2012 年發(fā)明,并逐漸取代 XML 成為事實上的數(shù)據(jù)交換格式標準。
JSON 基于 JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一個子集。但采用完全獨立于語言的文本格式,并使用了類似于 C 語言家族的習慣。
在 JSON 中,一共 6 種數(shù)據(jù)類型:
number:跟 Javascript 的數(shù)值一致,除去未曾使用的八進制與十六進制格式,和一些編碼細節(jié)
boolean:true 和 false
string:是由雙引號包圍的任意數(shù)量Unicode字符的集合,使用反斜線轉(zhuǎn)義
null:null
array:數(shù)組是值(value)的有序集合。一個數(shù)組以“[”(左中括號)開始,“]”(右中括號)結(jié)束,值之間使用“,”(逗號)分隔
object:對象是一個無序的“‘名稱/值’對”集合。一個對象以“{”(左括號)開始,“}”(右括號)結(jié)束,每個“名稱”后跟一個“:”(冒號);“‘名稱/值’ 對”之間使用“,”(逗號)分隔
以及上面的任意組合。
在 JavaScript 中有一個全局對象 JSON,包含兩個方法 JSON.stringify() 和 JSON.parse(),用于序列化和解析 JSON。
當然也有人使用 eval("(" + string + ")") 代替 JSON.parse() 來 解析JSON,相比而言這種方式的容錯性更高。
JSONP(JSON with Padding)因為 XMLHttpRequest 有同源策略,而在實際開發(fā)中又常常會有跨域的需求,早期開發(fā)者為了解決跨域問題而搞出來這樣一個頗為奇怪的東西。產(chǎn)生原因和名字一樣古怪,光聽名字恐怕沒幾個人知道說的是個什么東西。
剛好 標簽可以引用其他域下的靜態(tài)資源,想想我們有時候在站點引入的數(shù)據(jù)統(tǒng)計類的 JS。
但我們要的是數(shù)據(jù),而不是一段靜態(tài)的 JS 代碼,怎么辦?
這還不簡單嗎,讓服務器動態(tài)生成 js ,再把數(shù)據(jù)放進去不就可以嗎。為了區(qū)分每一份數(shù)據(jù),還需要針對返回的數(shù)據(jù)做一個標識,其實就是在數(shù)據(jù)外面包裹一個函數(shù)名。
然后需要瀏覽器端預先設置好這樣一個函數(shù),返回的數(shù)據(jù)就相當于一次執(zhí)行過程,對獲取數(shù)據(jù)的處理。
總結(jié)AJAX 是一類技術(shù)的集合,其中最重要的是 XMLHttpRequest
JSON 是一個數(shù)據(jù)交換格式,也是目前事實上的標準
JSONP 是為解決跨域問題搞出來的一種獲取數(shù)據(jù)的方式
舉個栗子接下來,用這個簡單的示例來說明如何通過 JSONP 的方式獲取數(shù)據(jù),以及它到底是怎樣工作的。
服務器這里使用 Node.js 返回一段簡單的數(shù)據(jù)。
/** * 一個簡單的 http 服務器,返回 json 數(shù)據(jù) * 跟 Node 主頁上的那個經(jīng)典例子沒太大差別 */ 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!") } });
這樣就很輕松的通過 JSONP 的方式獲取到數(shù)據(jù),我們似乎也不需要關心里面究竟是怎么一回事。但有時候肯能會有人問起:“為什么 jsonp 不能使用 POST 方法”的問題,其實稍微了解一下 JSONP 的原理,這種問題完全就不存在了。
雖然像 JQuery 這類庫將 JSONP 封裝到 $.Ajax() 上,但準確來講是不對的。因為 JSONP 只是通過動態(tài)地通過 標簽去請求一段 JS 代碼(或者叫數(shù)據(jù)),而非使用 XMLHttpRequest ,原理就像下面這樣:
對 JSONP 的簡單封裝/** * 對 JSONP 的一種簡單封裝 * * @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); }
這段代碼對 JSONP 進行一層簡單包裝,調(diào)用也很簡單:
getJsonp({ "url": "http://127.0.0.1:9999/", "callbackName": "log", "success": function(data) { console.log("我是回調(diào)函數(shù),我拿到數(shù)據(jù)了", data); } });
看上去代碼還挺長的,實際上核心代碼不多,分三步:
1.創(chuàng)建一個 標簽,并設置其 urlvar scriptElem = document.createElement("script"); scriptElem.setAttribute("src", url + "?callback=" + callbackName);2.設置回調(diào)函數(shù)
window[callbackName] = options.success;
這里簡單處理,直接把傳入的回調(diào)函數(shù)設置成全局的
3.調(diào)用document.querySelector("head").appendChild(scriptElem);
實際上就是把 加到 html 文檔中,這樣就會去加載標簽的內(nèi)容,也就是一個 JS 文件。
但通?,F(xiàn)實中跑的代碼內(nèi)容會更多,包含一些錯誤控制、參數(shù)拼接、超時處理、性能安全等方面的,但它仍然清楚地描述 JSONP 的原理。
安全早期的瀏覽器處于安全層面的考量,制定同源策略,限制了一個源(origin)中加載文本或腳本與來自其它源(origin)中資源的交互方式。
但是隨著互聯(lián)網(wǎng)的發(fā)展催生了跨域訪問進行數(shù)據(jù)交互的需求,于是 JSONP 就產(chǎn)生了,以及后來的 CORS 機制,允許 XMLHttpRequest 對象發(fā)起跨域的請求。
但是另一方面,也增加了安全風險,我們在使用的時候應當更加謹慎小心,防止 XSS、CSRF 等攻擊。
其他 數(shù)據(jù)預覽之前碰到一個問題,在調(diào)用一些接口返回的數(shù)據(jù)無法使用 Chrome 預覽,自己寫測試接口的時候也碰到過。后來發(fā)現(xiàn),只是因為沒有在 response 頭部加上 Content-Type: application/javascript,僅此而已。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/87744.html
摘要:前言最近因為工作的緣故,幾乎把市面上所有庫都下載了一遍,卻發(fā)現(xiàn)沒有百分百讓我滿意的,最后自己手動改寫了,才符合了要求,也因此有了這篇文章。在這一點上不得不說做的很好,的函數(shù)包含了對各種情況的處理,還偽造了一個狀態(tài)碼的返回。 前言 最近因為工作的緣故,幾乎把市面上所有Jsonp庫都下載了一遍,卻發(fā)現(xiàn)沒有百分百讓我滿意的,最后自己手動改寫了Jsonp,才符合了要求,也因此有了這篇文章。本文...
摘要:因為同源策略的限制,我們不能在與外部服務器進行通信的時候使用。這個是跨域服務器取數(shù)據(jù)的接口,參數(shù)為回調(diào)函數(shù)的名字,返回的格式為原理首先在客戶端注冊一個然后把的名字傳給服務器。 一、同源策略 同源策略,它是由Netscape提出的一個著名的安全策略,現(xiàn)在所有的可支持javascript的瀏覽器都會使用這個策略。 為什么需要同源策略,這里舉個例子: 假設現(xiàn)在沒有同源策略,會發(fā)生什么事...
閱讀 966·2023-04-26 02:49
閱讀 1177·2021-11-25 09:43
閱讀 2549·2021-11-18 10:02
閱讀 2923·2021-10-18 13:32
閱讀 1285·2019-08-30 13:54
閱讀 2081·2019-08-30 12:58
閱讀 3015·2019-08-29 14:06
閱讀 2155·2019-08-28 18:10