跳到主要內容

Ajax跨網域議題 - 使用JSONP取得資料

參考文章:【原創】說說JSON和JSONP,也許你會豁然開朗,含jQuery用例
                      使用 JSONP 跨站請求

JSON為JavaScript中常用的資料交換格式
簡單、輕型的特性讓他成為Web 開發的首選,這裡就不多提了

而在Web開發的過程中,我們有時會遇到跨網域存取資料的需求
不管是基於分散流量需求,又或者是使用雲端提供業者的服務
使用第三方提供的服務、資源
甚至在同一個專案目錄底下開發的檔案也可能因啟用HTTPS而導致網域的不同

我們有這麼多會碰上跨網域的情況
但Browser 本身的安全機制會禁止我們直接從其他網域取得資料
瀏覽器唯一能從其他網域取得資源的機會就是JavaScript的匯入
也因此衍伸出一個非官方的解決方案,也就是JSONP
JSONP的全名是JSON with Padding
這項技巧本身與JSON沒有實際關係,僅僅是因為JSON是實作上最使用的格式

JSONP簡單的來說即是利用JavaScript的動態載入
將JSON格式的資料讀取進來後,直接在JavaScript做處理
這與 AJAX是不同的技術方式
AJAX的目的是獲取目標頁面的資料,而JSONP則是獲取一段JavaScript程式碼

欲取得資料的頁面寫下類似下面這段程式碼:

    var head = document.getElementsByTagName('head')[0];
    var storeList = null;

//倒入JSON資料到storeList
var JSONDataGetter = function(data){
storeList = JSON.parse(JSON.stringify(data));
};

var src = "firmList.jsp";      //JSON資料提供頁面
var js = document.createElement('script');
js.setAttribute('src', src);
    if(head)
        head.appendChild(js);
    else
        document.body.appendChild(js);

上面這段的 JSONDataGetter() 會將傳入的JSON資料轉成JavaScript物件
接著是JSON資料提供頁面的程式碼
<%
response.setContentType("text/javascript");  //將頁面的型別設定為JavaScript

....  //JSP code

int counter = 0;
out.print("JSONDataGetter([");
    for(Map.Entry<String, HashMap<String, String>> m : totalMap.entrySet()){
    HashMap<String, String> store = m.getValue();
   
    if(counter == 0){
    out.print(String.format("{ \"storeName\" : \"%s\", \"storeType\" : \"%s\", \"storeLocation\" : \"%s\"}", m.getKey(), store.get("storeType"), store.get("storeLocation")));
    }else{
    out.print(String.format(", { \"storeName\" : \"%s\", \"storeType\" : \"%s\", \"storeLocation\" : \"%s\"}", m.getKey(), store.get("storeType"), store.get("storeLocation")));
    }
    counter++;
    }
    out.print("]);");

%>


大部分都是字串拼貼的處理,顯示出來大概就是下面這樣

JSONDataGetter([ //JSON資料]);

引入的JavaScript code的作用是呼叫 JSONDataGetter() 函式處理產生的JSON資料
實務上也會常看到在引入JavaScript的路徑上加上callback變數回傳
如:var src = "firmList.jsp?callback=XXX";
提供 JSON 資料的頁面再根據參數而輸出不同的字串,以便呼叫不同的處理函式
如此一來就能做到更多元的處理
這就是JSONP了

要說明的是JSONP送出資料是使用GET方式
如果有需要透過POST方法送出資料,可以參考Ajax跨網域議題 - 透過POST方法送出資料

留言