跨域概念 跨域是瀏覽器遵循同源策略,對頁面腳本的安全限制,不允許Javascript請求不同域的數據。 跨域的本質就是要解決同源策略的限制!假如有地址 http://www.example1.com:8080/a.jsp,如下請求是不符合同源策略限制的: 跨域之JSONP JSONP跨域是利用<sc ...
跨域概念
跨域是瀏覽器遵循同源策略,對頁面腳本的安全限制,不允許Javascript請求不同域的數據。
跨域的本質就是要解決同源策略的限制!假如有地址 http://www.example1.com:8080/a.jsp,如下請求是不符合同源策略限制的:
http://www.example1.com:8081/a.jsp 埠不一致
http://www.example2.com:8080/b.jsp 功能變數名稱不一致
https://www.example1.com:8080/a.jsp 協議不一致
跨域之JSONP
JSONP跨域是利用<script>標簽沒有跨域限制的特性,通過其src屬性模擬js文件載入,請求不同域的地址,返回符合Javascript語法的數據進行處理,從而間接實現跨域。
我們知道HTML中可以引入其他域的js、css等文件,JSONP正是利用這個特性,把src替換成我們要請求的不同域地址。伺服器接收到請求後,把JSON數據包到回調函數中響應,實際上<script>的src屬性仍舊載入了一段Javascript代碼,但這段代碼包含了我們伺服器響應的數據。頁面收到響應後可以像處理一般Javascript腳本一樣,進行調用、處理。
JSONP原理示例
服務端介面:
1 @RequestMapping(value="/getUser", method=RequestMethod.GET) 2 @ResponseBody 3 public String getUser(String callback, Integer id) { 4 String json = "{'id':'123', 'name':'xlog2n'}"; 5 String jsonp = callback + "(" + json + ")"; 6 return jsonp; 7 }
前端請求:
1 <script type="text/javascript"> 2 // 預先定義好回調函數 3 function handleUser(user) { 4 alert(user.id + ":" + user.name); 5 } 6 </script> 7 8 <!-- 實際的JSONP是動態創建script標簽 --> 9 <script type="text/javascript" src="http://xlog2n.com/getUser?callback=handleUser&id=123"></script>
實際使用jQuery進行JSONP請求時,<script>標簽是動態創建的,<script>標簽的src屬性指定了不同域的/getUser介面,並且傳遞了callback指明回調函數的名稱,當src載入完成後,實際是一段執行handleUser函數的Javascript代碼,參數是從服務端響應回來的JSON數據,其實JSONP就是JSON + P(包裝):
handleUser({'id':'123', 'name':'xlog2n'})
JSONP原理簡單、相容性好,jQuery發送JSONP請求也很方便,但是JSONP只支持GET方式的請求,對於POST跨域請求就無能為力了,究其原因<script>標簽的src屬性發出的請求和<img src=""/>一樣都是GET請求,所以JSONP無法支持POST請求!
jQuery JSONP調用示例
jquery把jsonp跨域請求集成到了ajax方法中,jsonp參數指定了回調參數的key,以下示例中我們在後端可以使用 request.getParameter('callback')獲取回調函數的名稱:
1 $.ajax({ 2 url: 'http://xlog2n.com/getUser', 3 dataType: 'jsonp', 4 jsonp: 'callback', 5 success: function(user) { 6 alert(user.id + ":" + user.name); 7 } 8 });
跨域之CORS
CORS是跨域資源共用標準,提供了一組HTTP頭信息,用來描述伺服器可以接受哪些來源、哪些方式的請求,從而保證了伺服器可以進行跨域請求的控制,只接受符合要求的跨域請求。
服務端響應頭設置
使用CORS跨域,只需要在反向代理如nginx中設置以下響應頭(也可以程式中設置,如HttpServletResponse.setHeader方法)
1 server { 2 listen 80; 3 server_name xlog2n.com; 4 location / { 5 add_header 'Access-Control-Allow-Origin' '*'; 6 add_header 'Access-Control-Allow-Methods' 'POST,GET,PUT,DELETE'; 7 add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,Cache-Control, ......'; 8 add_header 'Access-Control-Allow-Credentials' 'true'; 9 ...... 10 ...... 11 proxy_pass http://127.0.0.1:8080; 12 } 13 ...... 14 ...... 15 }
第一個頭信息Access-Control-Allow-Origin表示服務端接受的跨域請求來源,星號表示接受任何來源,我們也可以指定一個功能變數名稱,只接受該功能變數名稱下的跨域請求。
第二個頭信息Access-Control-Allow-Methods表示服務端接受的跨域請求方法,示例中只接受POST、GET、PUT、DELETE。
第三個頭信息Access-Control-Allow-Headers表示服務端接受的跨域請求頭信息,在需要對請求頭進行訪問控制時,設置該頭信息。
第四個頭信息Access-Control-Allow-Credentials表示服務端接受附帶身份驗證信息(Cookie)的跨域請求。要特別註意,如果設置該頭信息為true,Access-Control-Allow-Origin不能設置為星號,否則附帶身份驗證信息的請求會失敗。
預測請求
大家可能註意到,有些跨域請求會多發起一個請求OPTIONS請求,其實這個OPTIONS請求就是預測請求。預測請求是瀏覽器主動發起的,用來測試服務端是否支持這個即將發起的跨域請求。並非所有的跨域請求都會先發送一個預測請求,預測請求是符合條件才觸發的。
- 當跨域請求是非GET請求時
- 當跨域請求設置了Accept、Accept-Language(請自行百度會觸發的所有頭信息)
- 當跨域請求設置了Content-Type頭,但Content-Type值不為 application/x-www-form-urlencoded 或者 text/plain 或者 multipart/form-data 之一時
預測請求只有響應頭,沒有響應體。預測通過後實際的請求才會發起,也會收到相應的響應體。
CORS跨域POST請求示例
上文說到JSONP不支持POST請求,但CORS可以很方便的使用POST發送大量數據到後端:
1 <html> 2 <head> 3 <script src="jquery.min.js" type="text/javascript"></script> 4 <script src="jquery.json.min.js" type="text/javascript"></script> 5 </head> 6 <body> 7 <button>TEST</button> 8 9 <script type="text/javascript"> 10 var orderInfo = { 11 itemId: '1600000000000000301', 12 issueNo: 1, 13 skuNum: 1, 14 payPassword: '011455e004151e30fd1413da54e3d77d', 15 balanceFee: 0, 16 onlineFee: 100, 17 jingBeanFee: 0, 18 couponParams: [], 19 mobile: '158****6060', 20 activityType: 1, 21 screen: '111', 22 uuid: '78043a633e5a440bad90639c67225beb' 23 }; 24 25 $('button').on('click', function() { 26 var body = $.toJSON(orderInfo); 27 28 /* 29 // 方式一:使用原生JS發送Ajax POST跨域請求 30 var xhr = new XMLHttpRequest(); 31 if(xhr) { 32 xhr.open('POST', 'http://xlog2n.com/order', true); 33 xhr.setRequestHeader('Content-Type', 'application/json'); 34 xhr.onreadystatechange = function() { 35 if (xhr.readyState === 4) { 36 if (xhr.status === 200) { 37 alert(xhr.responseText); 38 } else{ 39 alert('錯誤:' + xhr.status); 40 } 41 } 42 }; 43 xhr.send(body); 44 } 45 */ 46 47 // 方式二:使用jQuery發送Ajax POST跨域請求 48 $.ajax({ 49 url: 'http://xlog2n.com/order', 50 type: 'post', 51 dataType: 'JSON', 52 data: body, 53 headers: {'Content-Type':'application/json'}, 54 success: function(data) { 55 alert(data); 56 } 57 }); 58 }); 59 60 </script> 61 </body> 62 </html>
CORS是比較新的標準,所以各瀏覽器支持的情況不一樣,尤其是那個什麼6、7、8,但是CORS跨域支持POST等請求方法,可以很好的支持大數據的提交。和JSONP各有優劣,使用哪種方式還需您自己定奪!!!
IFrame跨域問題
未完待續...