jQuery中Ajax+Spring MVC實現跨域請求
項目開發中,某個可獨立、也可整合的子業務模組需要向外開放相關API介面,先說下項目本身使用了jersery來實現RESTful webservice以名詞形式發布API。有意思的是在實際的操作中同事卻通過Ajax跨域請求的方式去調用該API,先不說成功與否,這種方式本就是“滑稽"的,和他一起探討了此種做法的不合理性,之後選擇jersey client的方式進行遠程調用。不過他在跨域請求中遇到了問題,自己閑暇時間予以解決,這才是此篇文章的由來。
jQuery對跨域請求有兩種解決方案分別是jQuery的jquery.ajax jsonp格式和jquery.getScript方式,而且這兩種方式都只支援get方法。這裡主要談的是jsonp跨域的實現。
json格式我們倒是經常使用,但是jsonp就不那麼常用了,所以首先需要對jsonp要有一個瞭解。
JSONP解釋
在解釋JSONP之前,我們需要瞭解下”同源策略“這個概念,這對理解跨域有協助。基於安全的原因,瀏覽器是存在同源策略機制的,同源策略阻止從一個源載入的文檔或指令碼擷取或設定另一個源載入額文檔的屬性。有點繞,說的簡單點就是瀏覽器限制指令碼只能和同協議、同網域名稱、同連接埠的指令碼進行互動。
JSONP就是為瞭解決這一問題的,JSONP是英文JSON with Padding的縮寫,是一個非官方的協議。他允許服務端產生script tags返回值用戶端,通過javascript callback的形式來實現網站訪問。JSONP是一種script tag的注入,將server返回的response添加到頁面是實現特定功能。
簡而言之,JSONP本身不是複雜的東西,就是通過scirpt標籤對javascript文檔的動態解析繞過了瀏覽器的同源策略。
JSONP原理及實現
接下來,來實際類比一個跨域請求的解決方案。後端為Spring MVC架構的,前端則通過Ajax進行跨域訪問。
1、首先用戶端需要註冊一個callback(服務端通過該callback(jsonp)可以得到js函數名(jsonpCallback)),然後以JavaScript語
法的方式,產生一個function
2、接下來,將JSON資料直接以入參的方式,放置到function中,這樣就產生了一段js文法文檔,返回給用戶端。
3、最後用戶端瀏覽器動態解析script標籤,並執行返回的JavaScript文法文檔片段,此時資料作為參數傳入到了預先定義好的
回呼函數裡(動態執行回呼函數)。
這種動態解析js文檔和eval函數是類似的。
接下來就是如何?了,用戶端代碼。
$.ajax({ type: "get", async: false, url: "http://localhost:8080/buy/get", dataType: "jsonp", jsonp: "callbackparam", //服務端用於接收callback調用的function名的參數 jsonpCallback: "success_jsonpCallback", //callback的function名稱,服務端會把名稱和data一起傳遞迴來 success: function(json) { alert(json[0].name); } });
註解:jsonp會建立一個查詢字串參數callback=?,這個參數會載入請求的URL後面,服務端應當在JSON資料前加上回呼函數
名,以便完成一個JSONP請求。也就是說伺服器端需要對返回的資料做處理,格式為如下形式:
jsonpCallback([{ name:"jhon"}]) 接下來看伺服器端針對上述代碼的處理:
@RequestMapping("/get")public void get(HttpServletRequest req,HttpServletResponse res) {res.setContentType("text/plain");String callbackFunName =req.getParameter("callbackparam");//得到js函數名稱try {res.getWriter().write(callbackFunName + "([ { name:\"John\"}])"); //返回jsonp資料} catch (IOException e) {e.printStackTrace();}}
前端Ajax跨域請求觸發之後,能夠有效得到JSON資料,情況如下:
至此,Ajax跨域請求也已經解決了,不過還是有兩點地方需要注意:
1、沒有關於JSONP調用的錯誤處理,動態插入的指令碼有效,則執行調用,無效就默默失敗(無任何提示)。
2、JSONP被不信任的服務使用會有一定的安全隱患,不信任的服務提供的指令碼可能是惡意的。