天天看點

使用jquery的getjson()遇到的跨域通路問題環境描述出問題代碼解決方案

環境描述

  • 伺服器:使用jersey提供RESTful接口
  • 用戶端:使用jquery的getJson()方法異步擷取資料
  • 希望實作的功能:伺服器端以json格式提供RESTful的資料通路,用戶端通過ajax異步加載的方式讀取資料。

出問題代碼

(其實下面代碼也不包含錯誤,隻是在執行的時候會出問題)

用戶端原始代碼:

document.getElementById("mydiv").innerHTML = "data";
$(function(){
     $.getJSON("******", function (data) {
         alert("go");
         document.getElementById("mydiv").innerHTML = "hahahah";
     });
});
           

伺服器端原始代碼:

@GET
@Path("/test")
@Produces("application/json;charset=utf8")
public String go(){
    return "({\"num\":\"3\"}";
}
           

結果運作的時候就出問題了,用戶端的回調函數死活不執行。用Firefox的Httpfox調試下,發現在擷取json資料的時候就遇到問題,報錯

application/json (NS_ERROR_DOM_BAD_URI)

網上找了下,說是jquery跨域通路的安全問題,就是說:

JavaScript出于安全方面的考慮,不允許跨域調用其他頁面的對象。但在安全限制的同時也給注入iframe或是ajax應用上帶來了不少麻煩。首先什麼是跨域,簡單地了解就是因為JavaScript同源政策的限制,a.com 域名下的js無法操作b.com或是c.a.com域名下的對象。

上邊的代碼中,用戶端和服務端确實在不同的伺服器,使用不同的IP位址和端口号,是以出現了問題。

解決辦法就是JSONP,全稱是 JSON with Padding ,是基于 JSON 格式的為解決跨域請求資源而産生的解決方案。其基本原理是利用了 HTML 裡 元素标簽可以跨域通路,是以将資料封裝成為js回調函數的格式進行傳輸通路。

舉個例子,上述的資料

{"num":"3"}

,這時不能跨域通路的,那麼救把它包裝為js,

callback('{"num":"3"}')

,将資料包裝為回調函數的參數,就可以跨域通路了。這就需要解決一個問題,提供資料通路的伺服器必須進行資料封裝的操作,如果響應的時候還是把原來的json格式資料輸出,那麼用戶端是拿不到需要的資料的。

如果說伺服器沒有對資料進行封裝,那麼出現的問題就是回調函數死活不執行。即使用Httpfox進行調試,也會發現雖然正确通路了資料連結,伺服器也傳回了資料,但回調函數就是執行不了。就是因為這個問題困了我整整兩天……

解決方案

其實jQuery已經封裝了JSONP的使用

$.getJSON( "****?jsoncallback=?", function( data ){
    // 處理跨域請求得到的資料
});
           

jquery會把

jsoncallback

後邊的

?

替換為一個字元串作為資料通路的回調函數的函數名,在伺服器端需要讀取該參數,然後使用它對資料進行封裝,也就是改成

f(data)

的樣式,加上函數名和括号就行了。

伺服器端代碼為:

@GET
    @Path("/test")
    @Produces("application/json;charset=utf8")
    public String go(@QueryParam("jsoncallback") String jsoncallback){
        System.out.println(jsoncallback);
        String info = jsoncallback+"({\"num\":\"3\"})";
        return info;
    }
           

ok,再通路就沒有問題了!

PS:最後吐槽一下網絡上的各種解決方案,都是隻給一個

jsoncallback

參數,伺服器需要怎麼改一點都不說,結果整整兩天一直困在回調函數不執行的苦惱中……

感謝基于JQuery、Jsonp與Jersey的跨域通路這篇文章替我找到了回家的路!