1. 程式人生 > >jQuery中Ajax+Spring MVC實現跨域請求

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被不信任的服務使用會有一定的安全隱患,不信任的服務提供的指令碼可能是惡意的。