這段時間面試 經常會問到這個問題。也就是說,如果你的前端想要擷取其他網域名稱下的資料,前端需要如何請求,後端需要如何設定。
最常見的處理方式有兩種
方法一,在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方式跨域的.
希望總結可以協助到大家