$.ajax跨域請求數據的解決方案

$.ajax跨域請求數據的解決方案

發表於2016/9/8 15:39:38  281人閱讀

分類: javascript/jquery

最近一直在搞公衆號前臺開發,遇到了ajax跨域請求的問題,像地區的省-市-縣三級聯動、汽車品牌-車系-車款的三級聯動查詢等都需要調用外部接口(其他工程項目的接口)完成。下面就分享一下個人解決跨域請求的方案,當然是在後臺程序猿大哥的幫助下,我才弄明白了其中的淵源,趕緊記錄下來慢慢積累,也希望對大家能有所幫助,還請積極提出意見或建議。

跨域請求需要藉助後臺代碼接收callback回調函數,對json數據進行進一步處理;前臺再用ajax請求向服務器發送callback參數,並指定數據格式爲jsonp。

一、後臺對跨域請求進行處理

1.CarBrandController.java(汽車品牌接口java文件),這裏列出的方法主要用來根據不同的level值查詢對應的品牌、車系、車款,在這裏對跨域請求做一個接收回調函數的處理,如果返回的callback爲null,則不是跨域請求,不需要做特殊處理,直接打印json接口數據即可;如果返回的callback不爲null,則表示跨域請求,這時要對json數據做一個特殊處理,即在json數據的外層加一對小括號包起來,具體請看HttpAdapter.java文件中的printlnJSONObject方法。

public void json(HttpServletRequest request,HttpServletResponse response){
    Map<String,Object>map=new HashMap<String, Object>();
    String id = request.getParameter("id");           //接收ajax請求帶過來的id
    String level = request.getParameter("level");     //接收ajax請求帶過來的level
    String callback=request.getParameter("callback"); //接收ajax請求帶過來的callback參數
    if ("1".equals(level)) {                          //如果level是'1',則查詢第一級目錄內容
        map.put("results", this.carBrandService.findByAttr(null, "first_letter asc"));  //調用查詢方法,結果放入map
    } else if ("2".equals(level)) {                   //如果level是'2',則查詢第二級目錄內容
        map.put("results", this.carSerieService.findByAttr("parent_id="+id, "first_letter asc"));//調用查詢方法,結果放入map
    } else if ("3".equals(level)) {                   //如果level是'3',則查詢第三極目錄內容
        map.put("results", this.carModelYearService.findByAttr("parent_id="+id, "jian_pin desc"));//調用查詢方法,結果放入map
    }
    map.put("level",level);
    if (null==callback) {                             //如果接收的callback值爲null,則是不跨域的請求,輸出json對象
        HttpAdapter.printlnObject(response, map);
    }else{                                           //如果接收的callback值不爲null,則是跨域請求,輸出跨域的json對象
	HttpAdapter.printlnJSONPObject(response, map, callback);
    }
}


2.HttpAdapter.java(輸出對象的java文件),printlnObject方法打印正常json字符串;printlnJSONObject方法對json字符串進行了特殊處理。

/**
 * 打印對象
 * @param response
 * @param object
*/
public static void printlnObject(HttpServletResponse response,Object object){
    PrintWriter writer=getWriter(response);
    writer.println(JSON.toJSONString(object));
}
/**
 * 打印跨域對象
 * @param response
 * @param object
*/
public static void printlnJSONPObject(HttpServletResponse response,Object object,String callback){
    PrintWriter writer=getWriter(response);
    writer.println(callback+"("+JSON.toJSONString(object)+")");
}

二、前臺ajax跨域請求數據

寫法1:向服務器發送一個參數callback=?,同時指定dataType爲'jsonp'的格式,跨域請求時指定的數據格式必須是jsonp的形式。


function loadData(obj,level,id,value){
    $.ajax({  
        url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id+'&callback=?',     //將callback寫在請求url後面作爲參數攜帶
        type:'GET',
        async:false,
        dataType:'jsonp',
        success:function(data){                
            console.log(data);                       
            //其他處理(動態添加數據元素)           
    });     
}		  	    


寫法2:callback不需要寫在url中,但是要指定jsonp參數爲'callback',並給jsonpCallback參數一個值。


function loadData(obj,level,id,value){
    $.ajax({  
        url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id,
        type:'GET',
        dataType:'jsonp',
        jsonp: 'callback',                    //將callback寫在jsonp裏作爲參數連同請求一起發送
        jsonpCallback:'jsonpCallback1',     
        success:function(data){                   	
        console.log(data);           
}); }

以上兩種寫法的含義是一樣的,只是寫法不同罷了。

接下來補充一下jsonp的工作原理。

三、jsonp跨域的原理解析

jsonp的最基本的原理是:動態添加一個<script>標籤,而script標籤的src屬性是沒有跨域的限制的。這樣說來,這種跨域方式其實與ajax XmlHttpRequest協議無關了.

JSONP是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過javascript callback的形式實現跨域訪問JSONP即JSON with Padding。由於同源策略的限制,XmlHttpRequest只允許請求當前源(域名、協議、端口)的資源。如果要進行跨域請求,我們可以通過使用html的script標記來進行跨域請求,並在響應中返回要執行的script代碼,其中可以直接使用JSON傳遞javascript對象。這種跨域的通訊方式稱爲JSONP。

jsonCallback 函數jsonp1236827957501(....): 是瀏覽器客戶端註冊的,獲取跨域服務器上的json數據後,回調的函數

Jsonp原理:

首先在客戶端註冊一個callback (如:'jsoncallback'), 然後把callback的名字(如:jsonp1236827957501)傳給服務器。注意:服務端得到callback的數值後,要用jsonp1236827957501(......)把將要輸出的json內容包括起來,此時,服務器生成 json 數據才能被客戶端正確接收。

然後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 'jsoncallback'的值 jsonp1236827957501 .

最後將 json 數據直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文檔,返回給客戶端。

客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文檔,此時javascript文檔數據,作爲參數,
傳入到了客戶端預先定義好的 callback 函數(如上例中jquery $.ajax()方法封裝的的success: function (json))裏.(動態執行回調函數)

可以說jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空間就是大量採用這種方式來實現跨域數據交換的) .JSONP是一種腳本注入(Script Injection)行爲,所以也有一定的安全隱患.

注意,jquey是不支持post方式跨域的.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章