標籤:style class blog code java http
上篇部落格介紹了同源策略和跨域訪問概念,其中提到跨域常用的基本方式:JSONP和CORS。 那這篇部落格就介紹JSONP方式。
JSONP原理 在同源策略下,在某個伺服器下的頁面是無法擷取到該伺服器以外的資料的,但img、iframe、script等標籤是個例外,這些標籤可以通過src屬性請求到其他伺服器上的資料。 而JSONP就是通過script節點src調用跨域的請求。 當我們通過JSONP模式請求跨域資源時,伺服器返回給用戶端一段javascript代碼,這段javascript代碼自動調用用戶端回呼函數。
舉個例子 用戶端http://localhost:8080訪問伺服器http://localhost:11111/user,正常情況下,這是不允許的。因為這兩個URL是不同域的。 若我們使用JSONP格式發送請求的話? http://localhost:11111/user?callback=callbackfunction 則伺服器返回的資料如下: callbackfunction({"id":1,"name":"test"}) 仔細看看伺服器返回的資料,其實就是一段javascript代碼,這就是函數名(參數)格式。 伺服器返回後,則自動執行callbackfunction函數。 因此,用戶端需要callbackfunction函數,以便使用JSONP模式返回javascript代碼後自動執行其回呼函數。
注意:其中url地址中的callback和callbackfunction是隨意命名的。
具體的JS實現JSONP代碼。 JS中:
<script> var url = "http://localhost:8080/crcp/rcp/t99eidt/testjson.do?jsonp=callbackfunction"; var script = document.createElement('script'); script.setAttribute('src', url); //load javascript document.getElementsByTagName('head')[0].appendChild(script); //回呼函數 function callbackfunction(data){var html=JSON.stringify(data.RESULTSET);alert(html); } </script> 伺服器代碼Action: 後台返回的json外面需要由回呼函數包裹。具體的方法如下:
public class TestJson extends ActionSupport{@Overridepublic String execute() throws Exception {try {JSONObject jsonObject=new JSONObject();List list=new ArrayList();for(int i=0;i<4;i++){Map paramMap=new HashMap();paramMap.put("bank_no", 100+i);paramMap.put("money_type", i);paramMap.put("bank_name", i);paramMap.put("bank_type", i);paramMap.put("bank_status", 0);paramMap.put("en_sign_ways", 1);list.add(paramMap);}JSONArray rows=JSONArray.fromObject(list);jsonObject.put("RESULTSET", rows);HttpServletRequest request=ServletActionContext.getRequest();HttpServletResponse response=ServletActionContext.getResponse();response.setContentType("text/javascript");boolean jsonP = false;String cb = request.getParameter("jsonp");if (cb != null) { jsonP = true; System.out.println("jsonp"); response.setContentType("text/javascript");} else {System.out.println("json"); response.setContentType("application/x-json");}response.setCharacterEncoding("UTF-8");Writer out = response.getWriter();if (jsonP) { out.write(cb + "("+jsonObject.toString()+")"); System.out.println(jsonObject.toString());}else{out.write(jsonObject.toString()); System.out.println(jsonObject.toString());}} catch (Exception e) {e.printStackTrace();} return null;}}
JQUERY實現JSONP代碼。 Jquery從1.2版本開始也支援JSONP的實現。
$(function(){ jQuery.getJSON("http://localhost:8080/crcp/rcp/t99eidt/testjson.do?jsonp=?",function(data){ var html=JSON.stringify(data.RESULTSET);$("#testjsonp").html(html);} ); }); 第一個?代表後面是參數,與咱們一般調用一樣。重要的是第二個?,則是jquery動態給你產生毀掉函數名稱。
至於後台代碼和上述一致,使用同一個後台。
JQUERY中Ajax實現JSONP代碼。
$.ajax({ type:"GET", async :false, url:"http://localhost:8080/crcp/rcp/t99eidt/testjson.do", dataType:"jsonp", success:function(data){ var html=JSON.stringify(data.RESULTSET); $("#testjsonp").html(html); }, error:function(){ alert("error"); } }); 注意:這種形式,預設的參數是callback,而不是會是其他。則action代碼中擷取calback值則 String cb=request.getParameter("callback"); 並且產生的回呼函數,預設也是類似上述一大串數字。 根據Ajax手冊,更改callback名稱以及回呼函數名稱。 http://www.w3school.com.cn/jquery/ajax_ajax.asp jsonp:jsonp,則請求的地址為:http://localhost:8080/crcp/rcp/t99eidt/testjson.do?jsonp=自動產生回呼函數名 jsonpCallback:callbackfunction,則請求的地址為: http://localhost:8080/crcp/rcp/t99eidt/testjson.do?jsonp=callbackfunction 最後返回前台的是: callbackfunction(具體的json值)
其中上述JS實現JSONP代碼中,若不是動態拼接script指令碼,而是直接寫script標籤,類似如下: <script type="text/javascript" src=""></script> 若這樣寫的話,通過debug發現,的確正確返回了,但是一直提示找不到回呼函數。即使js也提供了回呼函數【各個瀏覽器都測試】 若要通過JS來顯示,則通過代碼動態create script標籤。
JSONP跨域方式,很方便,同時也支援大多部分瀏覽器,但是唯一缺點是,只支援GET提交方式,不支援其他POST提交。 若url地址傳輸的參數過多,如何?呢?下篇部落格會講解另一種跨域方案CROS原理以及具體調用樣本。