用jQuery.ajaxSetup實現對請求和響應資料的過濾,jqueryajaxsetup
不知道同學們在做項目的過程中有沒有相同的經曆呢?在使用 ajax 的時候,需要對請求參數和響應資料進行過濾處理,比如你們覺得就讓請求參數和響應資訊就這麼赤裸裸的在互連網裡來回的穿梭,比如這樣:
要知道,在浩瀚的互連網中,所有的資訊都是不安全的,萬一有人偷窺我們怎麼辦?!萬一被別人看見了我們的美體,偷窺到了我們的私處,然後以此威脅我們,豈不是太難堪了不是?這時,你或許會想給請求資料和響應資料加密,就相當於給我們的資料穿上了一層衣服。於是我們這樣:
是不是美美噠,對,穿上一層漂漂亮亮的衣服,就不怕別人偷窺我們的美體了,我們出門的時候要穿衣服,回家的時候也要脫衣服,也就是說ajax請求的參數需要加密,ajax響應的資料的要解密,如果說項目只有幾個ajax請求需要加密的話還OK,發請求之前把data處理一遍,success回呼函數把responseText解密一遍就完了。可是倘若架構大一點,ajax請求多一點,每次請求響應都要單獨處理加密解密啟不是太冗餘了,於是我便去翻閱jQuery ajax參考手冊,還真的有不小的收穫。
首先jQuery有一個 ajaxSetup 方法,該方法可以設定全域 ajax 初始化參數,也就是說在聲明了該方法之後的所有 ajax 請求都會預設使用該方法設定的初始值。
然後我們再翻閱 ajax 參數,突然,我眼前一亮!有一個叫做 beforeSend 的方法,我一看這名字就亮了!這個函數也就是在發送 ajax 請求之前的回呼函數,於是我們先把它用起來:
$.ajaxSetup({ beforeSend: function() { console.log(arguments);//我們先來看看這裡面有什麼好玩的東西 } });
然後我們在隨便發一個 ajax 請求:
$.ajax({ url: 'SetupServlet', type: 'GET', data: { param1: 'test1', param2: 'test2', } });
在控制台我們可以看見列印的參數列表有兩個對象,我們先來看看 W3C 裡對 beforeSend 的解釋:
- beforeSend(XHR)
- 類型:Function
- 發送請求前可修改 XMLHttpRequest 對象的函數,如添加自訂 HTTP 頭。
- XMLHttpRequest 對象是唯一的參數。
- 這是一個 Ajax 事件。如果返回 false 可以取消本次 ajax 請求。
實際上這裡是不對的,因為XHR不是唯一的參數,XHR只是 arguments[0] ,我們還有一個 arguments[1],我們來看看這是什麼東西:
以下是在 Firefox Developer Edition(Firefox 的開發人員版本,最近發現的,絕得超好用) 中列印的東西:
看到這裡我們大致明白了,我們這個對象大致就是 ajax 的參數對象,由於我們本次實驗的目的是給我們將要在互連網中遨遊的資料穿衣服,那麼我們看看這個衣服該穿在哪呢?在這個對象的 url 我們可以看到,jQuery 的 ajax 操作已經我們之前傳進來的參數序列化並附加在了 url 後面,因為這是 GET 請求。那麼 POST 請求長什麼樣呢?我們再來試一下:
$.ajax({ url: 'SetupServlet', type: 'POST', data: { param1: 'test1', param2: 'test2', }, });
現在這個參數對象長這個樣子:
我們可以看到不同之處在於 POST 請求多了一個 data 屬性,並且 url 後面沒有參數序列化字串,但是 data 屬性卻是序列化之後的參數字串。至此我們已經可以在 beforeSend 函數中對請求前的參數進行修改了,GET 請求修改 url 後面的參數,POST 請求修改 data 中的值,具體效果在這裡暫時不示範。
但是到這裡我依舊不是很爽啊,因為無論是 GET 還是 POST 的,我得到的都是序列化之後的字串,要修改參數的話得先還原序列化,然後才能處理,於是我又在 ajax API 當中尋找,功夫不負有心人,我找到了一個叫做 processData 的東西,先來看看官方解釋:
- processData
- 類型:Boolean
- 預設值: true。預設情況下,通過data選項傳遞進來的資料,如果是一個對象(技術上講只要不是字串),都會處理轉化成一個查詢字串,以配合預設內容類型 "application/x-www-form-urlencoded"。如果要發送 DOM 樹資訊或其它不希望轉換的資訊,請設定為 false。
也就是說預設情況下 jQuery 會自動幫我們把參數序列化,那麼我們現在把它設定為 false 看看會發生什麼:
$.ajaxSetup({ beforeSend: function() { console.log(arguments); }, processData: false, });
這時請求中的參數會發生如下變化
GET:
POST:
這裡我只截取部分,我們看到我們傳進來的參數在 POST 請求就是原生的對象,終於得到我想要的東西了,此時此刻我心中大喜!必須得抽根煙祝祝性,額不對...是祝祝興。於是我們可以拿這個 data 盡情的蹂躪,隨意的鞭打,我要把這個 data 對象盡情的踐踏!額,不好意思有點激動。回到正題,我們要給 data 穿衣服才對嘛,怎麼說著說著就要開始脫衣服了...好的,下面我們開始穿衣服,在這裡我以 base64 舉例,我對請求的參數進行 base64 編碼:
$.ajaxSetup({ beforeSend: function() { console.log(arguments); var params = arguments[1].data; var data = ''; for (var key in params) { //這兩行代碼的意思是進行 base64 編碼 var dataUtf8 = CryptoJS.enc.Utf8.parse(params[key]); var dataBase64 = CryptoJS.enc.Base64.stringify(dataUtf8); data = data.concat('&' + key + '=' + dataBase64); }; arguments[1].data = data.substring(1, data.length);//將序列化後的參數重寫 }, processData: false, });
於是乎,我們的請求參數就穿上了一身漂漂亮亮的衣服遨遊在互連網的世界裡了,因為 jquery 在 GET 方法中會自動把 data 附加在 url 後面,所以將 processData 設定為 false 之後 url 後面會出現 [object object] ,這是 javascript 對象 toString() 過後的結果,也就是說我們的這個方法並不很適合 GET 方法,所以想給資料穿衣服的同學們還是乖乖的使用 POST 方法吧。
講到這裡,發送資料我們解決了,但是接受資料呢?如果接受的資料也是進行加密的話,我們還需要對資料進行解密(說到這裡還是得脫衣服[捂臉]),我們繼續翻閱 API ,於是我又看到了一個叫做 dataFilter 的東西,老規矩,先看官方解釋:
- dataFilter
- 類型:Function
- 給 Ajax 返回的未經處理資料的進行預先處理的函數。提供 data 和 type 兩個參數:data 是 Ajax 返回的未經處理資料,type 是調用 jQuery.ajax 時提供的 dataType 參數。函數返回的值將由 jQuery 進一步處理。
該函數很簡單,就兩個參數,arguments[0] 是 ajax 的原始響應資料,也就是 XHR.responseText ,arguments[1] 是 ajax 請求參數中的 dataType ,而這個函數返回的值也就是 success 回呼函數中的 responseText,這下就非常好辦了,我們先來測試下:
前端代碼發送 ajax 請求,後台響應一句 "hello" ,然後我們在 dataFilter 裡返回一句 "world"
前端代碼:
$.ajaxSetup({ beforeSend: function() { console.log(arguments); var params = arguments[1].data; var data = ''; for (var key in params) { //這兩行代碼的意思是進行 base64 編碼 var dataUtf8 = CryptoJS.enc.Utf8.parse(params[key]); var dataBase64 = CryptoJS.enc.Base64.stringify(dataUtf8); data = data.concat('&' + key + '=' + dataBase64); }; arguments[1].data = data.substring(1, data.length);//將序列化後的參數重寫 }, processData: false, dataFilter: function() { console.log(arguments);//這是我的一個習慣,拿到一個函數之後,管他是什麼東西,先看看裡面有什麼參數 return "world"; } }); $.ajax({ url: 'SetupServlet', type: 'POST', dataType: 'text', data: { param1: 'test1', param2: 'test2', }, success: function(responseText) { console.log(responseText); }, });
後台代碼(java):
String param1 = request.getParameter("param1"); String param2 = request.getParameter("param2"); System.out.println("param1: " + param1); System.out.println("param2: " + param2); response.getWriter().write("hello");
後端輸出:
前端輸出:
看來一切正常,現在我們加密和解密的過程進行一條龍的處理:
前端:
$.ajaxSetup({ beforeSend: function () { var params = arguments[1].data; var data = ''; for (var key in params) { var dataUtf8 = CryptoJS.enc.Utf8.parse(params[key]); var dataBase64 = CryptoJS.enc.Base64.stringify(dataUtf8); data = data.concat('&' + key + '=' + dataBase64); }; arguments[1].data = data.substring(1, data.length); }, processData: false, dataFilter: function () { var result = ''; try { var a = CryptoJS.enc.Base64.parse(arguments[0]); var result = CryptoJS.enc.Utf8.stringify(a); } catch(e) { result = arguments[0]; } finally { return result; } } });
後台:
String param1 = request.getParameter("param1"); String param2 = request.getParameter("param2"); byte[] buffer1 = Base64.decodeBase64(param1); byte[] buffer2 = Base64.decodeBase64(param2); System.out.println("param1: " + new String(buffer1)); System.out.println("param2: " + new String(buffer2)); response.getWriter().write(Base64.encodeBase64String("hello".getBytes()));
後台輸出:
前端輸出:
至此已經大功告成了,讓我們來總結下我們使用過的東西
第一個: ajaxSetup 這是設定全域的初始屬性
然後是三個屬性:
beforeSend:發送前執行的函數
processData:預設不序列化參數
dataFilter:對響應的資料進行過濾
然後,我們就可以給我們的資料穿上一層漂漂亮亮的衣服了。
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的協助,同時也希望多多支援幫客之家!