jQuery的$.ajax
在介紹JSONP之前,先簡單的介紹一些JSON。JSON是JavaScript Object Notation的縮 寫,是一種輕量的、可讀的基於文本的數據交換開放標准。源於JavsScript編程語言中對簡 單數據結構和關聯數組的展示功能。它是僅含有數據對和簡單括號結構的純文本,因此可通過許多途徑進行JSON消息的傳遞。 1. JSONP定義 JSONP是英文JSON with Padding的縮寫,是一個非官方的協議。它允許在服務器端生成script tags返回至客戶端,通過javascript callback的形式來實現站點訪問。 JSONP是一種script tag的注入,將server返回的response添加到頁面實現特定功能。 2.JSONP由來 要解釋JSONP的來由,先要說一下瀏覽器的“同源策略(SOP:Same Origin Policy)”。 簡而言之,就是瀏覽器限制腳本程序只能和同協議、同域名、同端口的腳本進行交互,這包括共享和傳遞變量等。cookie的傳遞也是遵從同樣策略。這就造成一些涉及到多個服務器的應用在整合時一些麻煩。跨域訪問的問題造成A站點的Ajax代碼無法訪問B站點的數據。 如何解決跨域訪問呢?那就要借助瀏覽器的一個特性:盡管瀏覽器不允許頁面中的腳本程序跨域 讀取數據,但卻允許HTML引用跨域的資源,如圖片,CSS和腳本程序。對於腳本程序的引用比較特殊, 它被瀏覽器解析以后,就和本地的腳本程序別無二致且可立即進行解釋並執行。 如在B站點的一個js文件,一個簡單的提示框:alert(“This is Victor!”);。 在A站點引用這個js,這個腳本就會在B站點的應用中執行,顯示一個alert信息。 由於站外腳本的引用是通過script tag來實現的,而腳本程序又可通過DOM的方式可以對HTML頁面的所有標簽進行控制 (包括動態的創建script標簽),這就可以實現通過調用站外程序對本地資源進行更改了。 另外,通過"script",標記的使用,就可從服務端直接返回可執行的JavaScript函數調用或者JSON數據。 3. JSONP原理與實現 首先在客戶端注冊一個callback, 然后把callback的名字傳給服務器。此時,服務器先生成 JSON數據。然后以JavaScript 語法的方式,生成一個function, function名字就是傳遞上來的參數jsonp. 然后,將JSON數據直接以入參的方式,放置到function中,這樣就生成了一段 js 語法 最后,在客戶端瀏覽器中解析script標簽,並執行返回的JavaScript文檔,此時數據作為參數,傳入到了客戶端預先定義好的回調函數里(動態執行回調函數) 。 其實 JSONP是個很簡單的一個東西。主要是利用了script標簽對javascript文檔的動態解析來實現。(其實也可以用eval函數) <script type="text/javascript"> function jsonpCallback(result){ alert(result.msg); } </script> <script type="text/javascript" src="http://mydomain.com/jsonService?jsonp=jsonpCallback"></script> 注解: jsonCallback是獲取跨域服務器上的JSON數據后的客戶端的回調函數。 http://mydomain.com/jsonService?jsonp=jsonpCallback是獲取跨域服務器JSON數據的接口,參數為回調函數的名字。 返回的格式為:jsonpCallback({ msg:'this is json data'} ) 4. jQuery與JSONP 從1.2版本開始,jQuery擁有對JSONP回調的本地支持。 如果指定了JSONP回調,就可以加載位於另一個域的JSON數據. 回調的語法為:url?callback=?。jQuery自動將?替換為要調用的生成函數名。 jQuery回調函數: <script type="text/javascript"> jQuery.getJSON(url+"&callback=?",function(data){ alert("Name: " + data.name + ", Phone: " + data.phone); }); </script> 為此,jQuery 將一個全局函數附加到插入腳本時需要調用的窗口對象。 另外,jQuery 也能優化非跨域調用。如果向同一個域發出請求, jQuery 就將其轉化為普通 Ajax 請求。 5. JSONP的安全問題 在JavaScript 程序中有多種方法可動態地生成代碼,最著名的函數之一就是 eval()。 該函數允許您將任意字符串做為 JavaScript 代碼執行。然而,隨意使用該函數是非常危險的。 遺憾的是,一些使用廣泛的 JavaScript 庫在內部都直接使用 eval() 函數。 JSON本身是安全的,不含有賦值和調用。但由於 JSON 是以 JavaScript 的一個子集為基礎的, 所以腳本內容會潛在地包含惡意代碼。 由於許多 JavaScript 庫使用 eval() 函數將 JSON 轉換成 JavaScript 對象, 利用這點,攻擊者就可以向這些庫發送畸形的 JSON 對象,這樣 eval() 函數就會執行這些惡意代碼。 為保護 JSON 的使用,可使用RFC 4627 中所定義的正則表達式確保 JSON 數據中不包含活動的部分 <script type="text/javascript"> var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(text.replace(/"(\\.|[^"\\])*"/g,''))) && eval('(' + text + ')'); </script> 6. JSONP的缺陷 JSONP 是構建 mashup 的強大技術,但不幸的是,它並不是所有跨域通信需求的萬靈葯。它有一些缺陷,必須認真考慮它們。 第一,也是最重要的一點,沒有關於 JSONP 調用的錯誤處理。如果動態腳本插入有效,就執行調用; 如果無效,就靜默失敗。失敗是沒有任何提示的。 例如,不能從服務器捕捉到 404 錯誤,也不能取消或重新開始請求。 不過,等待一段時間還沒有響應的話,就不用理它了。 (未來的 jQuery 版本可能有終止 JSONP 請求的特性)。 第二, JSONP 被不信任的服務使用時會很危險。 因為 JSONP 服務返回打包在函數調用中的 JSON 響應, 而函數調用是由瀏覽器執行的,這使宿主 Web 應用程序更容易受到各類攻擊。 如果打算使用 JSONP 服務,了解它能造成的威脅非常重要。
作為一名努力往上爬的前端工程師,我這里介紹一下$.ajax中部分參數的功能使用。
url: 要求為String類型的參數,(默認為當前頁地址)發送請求的地址。 type:要求為String類型的參數,請求方式(post或get)默認為get。 注意其他http請求方法,例如put和delete也可以使用,但僅部分瀏覽器支持。 timeout: 要求為Number類型的參數,設置請求超時時間(毫秒)。此設置將覆蓋$.ajaxSetup()方法的全局設置。 async:要求為Boolean類型的參數,默認設置為true,所有請求均為異步請求。 如果需要發送同步請求,請將此選項設置為false。注意,同步請求將鎖住瀏覽器,用戶其他操作必須等 待請求完成才可以執行。 cache:要求為Boolean類型的參數,默認為true(當dataType為script時,默認為false)。 設置為false將不會從瀏覽器緩存中加載請求信息。 data: 要求為Object或String類型的參數,發送到服務器的數據。如果已經不是字符串,將自動轉換為字符串格 式。get請求中將附加在url后。防止這種自動轉換,可以查看processData選項。對象必須為key/value格 式,例如{foo1:"bar1",foo2:"bar2"}轉換為&foo1=bar1&foo2=bar2。如果是數組,JQuery將自動為不同 值對應同一個名稱。例如{foo:["bar1","bar2"]}轉換為&foo=bar1&foo=bar2。 dataType: 要求為String類型的參數,預期服務器返回的數據類型。如果不指定,JQuery將自動根據http包mime 信息返回responseXML或responseText,並作為回調函數參數傳遞。 可用的類型如下: xml:返回XML文檔,可用JQuery處理。 html:返回純文本HTML信息;包含的script標簽會在插入DOM時執行。 script:返回純文本JavaScript代碼。不會自動緩存結果。除非設置了cache參數。注意在遠程請求 時(不在同一個域下),所有post請求都將轉為get請求。 json:返回JSON數據。 jsonp:JSONP格式。使用SONP形式調用函數時,例如myurl?callback=?,JQuery將自動替換后一個 “?”為正確的函數名,以執行回調函數。 text:返回純文本字符串。 beforeSend:要求為Function類型的參數,發送請求前可以修改XMLHttpRequest對象的函數,例如添加自定義 HTTP頭。在beforeSend中如果返回false可以取消本次ajax請求。XMLHttpRequest對象是惟一的參 數。 function(XMLHttpRequest){ this; //調用本次ajax請求時傳遞的options參數 } complete:要求為Function類型的參數,請求完成后調用的回調函數(請求成功或失敗時均調用)。 參數:XMLHttpRequest對象和一個描述成功請求類型的字符串。 function(XMLHttpRequest, textStatus){ this; //調用本次ajax請求時傳遞的options參數 } success:要求為Function類型的參數,請求成功后調用的回調函數,有兩個參數。 (1)由服務器返回,並根據dataType參數進行處理后的數據。 (2)描述狀態的字符串。 function(data, textStatus){ //data可能是xmlDoc、jsonObj、html、text等等 this; //調用本次ajax請求時傳遞的options參數 error:要求為Function類型的參數,請求失敗時被調用的函數。該函數有3個參數,即XMLHttpRequest對象、錯 誤信息、捕獲的錯誤對象(可選)。 ajax事件函數如下: function(XMLHttpRequest, textStatus, errorThrown){ //通常情況下textStatus和errorThrown只有其中一個包含信息 this; //調用本次ajax請求時傳遞的options參數 } contentType:要求為String類型的參數,當發送信息至服務器時,內容編碼類型默認 為"application/x-www-form-urlencoded"。該默認值適合大多數應用場合。 dataFilter:要求為Function類型的參數,給Ajax返回的原始數據進行預處理的函數。 提供data和type兩個參數。data是Ajax返回的原始數據,type是調用jQuery.ajax時提供的 dataType參數。函數返回的值將由jQuery進一步處理。 function(data, type){ //返回處理后的數據 return data; } global:要求為Boolean類型的參數,默認為true。表示是否觸發全局ajax事件。設置為false將不會觸發全局 ajax事件,ajaxStart或ajaxStop可用於控制各種ajax事件。 ifModified:要求為Boolean類型的參數,默認為false。僅在服務器數據改變時獲取新數據。 服務器數據改變判斷的依據是Last-Modified頭信息。默認值是false,即忽略頭信息。 jsonp:要求為String類型的參數,在一個jsonp請求中重寫回調函數的名字。 該值用來替代在"callback=?"這種GET或POST請求中URL參數里的"callback"部分,例如 {jsonp:'onJsonPLoad'}會導致將"onJsonPLoad=?"傳給服務器。 username:要求為String類型的參數,用於響應HTTP訪問認證請求的用戶名。 password:要求為String類型的參數,用於響應HTTP訪問認證請求的密碼。 processData:要求為Boolean類型的參數,默認為true。默認情況下,發送的數據將被轉換為對象(從技術角度 來講並非字符串)以配合默認內容類型"application/x-www-form-urlencoded"。如果要發送DOM 樹信息或者其他不希望轉換的信息,請設置為false。 scriptCharset:要求為String類型的參數,只有當請求時dataType為"jsonp"或者"script",並且type是GET時 才會用於強制修改字符集(charset)。通常在本地和遠程的內容編碼不同時使用。
同域內的ajax
/*xxx.json的數據如下*/ {"name":'張三',"age":25,"sex":"男"}
/* 同域ajax是同一個域名和站點下,例如: 本站是:http://wap.cmread.com 請求地址是http://wap.cmread.com/xxx.json */ var ajaxUrl = 'http://wap.cmread.com/xxx.json'; $.ajax({ type:'get',/*請求類型get還是post*/ url:ajaxUrl,/*請求地址*/ cache:false,/*是否緩存,false不緩存*/ success:function(returnData){/*請求成功之后的回調函數*/ console.log(returnData); }, error:function(){/*失敗后的回調函數*/ console.log('error'); } });
跨域的ajax
/* 跨域ajax是不同域名和站點下的異步請求,例如: 本站是:http://wap.cmread.com/r 請求地址是http://wap.cmread.com/rbc/xxx.json */ /*xxx.json的數據如下*/ {"name":'張三',"age":25,"sex":"男"} var ajaxUrl = 'http://wap.cmread.com/rbc/xxx.json'; /*下面這個是同一域名不同站點的跨域*/ $.ajax({ type:'get',/*請求類型get還是post*/ url:ajaxUrl,/*請求地址*/ dataType:'jsonp', cache:false,/*是否緩存,false不緩存*/ success:function(returnData){/*請求成功之后的回調函數*/ console.log(returnData); }, error:function(){/*失敗后的回調函數*/ console.log('error'); } }); /*下面這個是不同域名不同站點的跨域*/ /* 跨域ajax是不同域名和站點下的異步請求,例如: 本站是:http://wap.cmread.com/r 請求地址是http://www.baidu.com/xxx.json 一般這種跨域形式都會有一個callback回調函數返回, 需要前端和后端匹配callback使用才能成功進入到success函數, 否則都屬於請求失敗error */ /*xxx.json的數據如下*/ callback({"name":'張三',"age":25,"sex":"男"}) var ajaxUrl = 'http://www.baidu.com/xxx.json'; $.ajax({ type:'get', url:ajaxUrl, cache:false, dataType:'jsonp',/*跨域數據類型jsonp不是json而是以一種script形式返回*/ jsonp:'jsonpCallback',/*重寫回調函數名*/ jsonpCallback:'callback',/*重寫回調函數名指定服務端返回的callback名*/ success:function(returnData){/*成功回調函數*/ console.log(returnData); }, error:function(){/*失敗回調函數*/ console.log('error'); } });