這段時間面試 經常會問到這個問題。也就是說,如果你的前端想要獲取其他域名下的數據,前端需要如何請求,后端需要如何設置。
最常見的處理方式有兩種
方法一,在java代碼中設置response.setHeader("Access-Control-Allow-Origin","*");即可解決ajax跨域的問題,其中星號代表允許全部請求
$.ajax({ type: "post", url: "http://192.168.1.88/testAjaxJson", contentType: "application/json", dataType: "json", success: function(){ alert("request succeed"); } });
@Controller public class TestController { /** * 使用普通json方式跨域請求 * @param response */ @RequestMapping(value="/testAjaxJson") public void testAjaxJson(HttpServletResponse response){ try { // 這里設置為任意域請求都能獲取到數據 response.setHeader("Access-Control-Allow-Origin","*"); // 這里還可以設置接收方式,固定域 二者選其一 response.setHeader("Access-Control-Allow-Headers", "accept, content-type"); response.setHeader("Access-Control-Allow-Method", "POST"); response.setHeader("Access-Control-Allow-Origin", "http://192.168.1.88");
response.getWriter().print("{\"id\":1}"); response.flushBuffer(); } catch (Exception e) { e.printStackTrace(); } } }
在正式post之前,瀏覽器會先發出一個options請求(也叫preflight),同時header帶上origin還有Access-Control-Request-*:**之類的頭,服務器響應會返回相應的access-control-allow-origin,如果匹配,那么瀏覽器就會發送正式post,否則就會出現上述錯誤。這也解答了,跨域訪問時,我們明明發送的post請求,失敗的話,查看chrome network會發現是options方法的原因。
這里的content-type不屬於(application/x-www-form-urlencoded,multipart/form-data,text/plain)中的任何一種,所以是復雜請求。
復雜請求 第一次是options請求,http options請求跟get、post、head等一樣,都屬於http的請求方法,options方法,用來獲取服務器端某url支持的方法,response header中allow標志支持的方法
第二次才是真正的請求
方法二,使用jsonp的方式請求數據,后端需返回js方法調用,返回的數據放在參數中
function testJsonp(){ $.ajax({ url:"http://192.168.1.88/testAjaxJsonp", type:"GET",//必須是get請求 dataType:"jsonp",//請求的數據類型 jsonp:"callback",//請求類型是回調 jsonpCallback:"callbackFunction",//數據請求成功時回調的方法 data:{ },//請求的數據 success:function(data){//執行完成返回的數據 alert(data.id);//輸出值是1 } }); }
@Controller public class TestController { @RequestMapping(value="/testAjaxJsonp") public void testAjaxJsonp(@RequestParam String callback,HttpServletResponse response){ try {
// 這里jsonp返回的數據是固定格式 文后有詳細解釋 response.getWriter().print(callback+"({\"id\":1})"); response.flushBuffer(); } catch (Exception e) { e.printStackTrace(); } } }
jsonp跨域的原理解析
jsonp的最基本的原理是:動態添加一個<script>標簽,而script標簽的src屬性是沒有跨域的限制的。這樣說來,這種跨域方式其實與ajax XmlHttpRequest協議無關了.
JSONP是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過javascript callback的形式實現跨域訪問JSONP即JSON with Padding。由於同源策略的限制,XmlHttpRequest只允許請求當前源(域名、協議、端口)的資源。如果要進行跨域請求,我們可以通過使用html的script標記來進行跨域請求,並在響應中返回要執行的script代碼,其中可以直接使用JSON傳遞javascript對象。這種跨域的通訊方式稱為JSONP。
jsonCallback 函數jsonp123(....): 是瀏覽器客戶端注冊的,獲取跨域服務器上的json數據后,回調的函數
Jsonp原理:
首先在客戶端注冊一個callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp123)傳給服務器。注意:服務端得到callback的數值后,要用jsonp123(......)把將要輸出的json內容包括起來,此時,服務器生成 json 數據才能被客戶端正確接收。
然后以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 'jsoncallback'的值 jsonp123
最后將 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方式跨域的.
希望總結可以幫助到大家
