Access control allow origin 簡單請求和復雜請求


錯誤信息

XMLHttpRequest cannot load http://web.image.myqcloud.com/photos/v2/10008653/bhpocket/0/?sign=4FcLKd5B8…p4SkFVUEJtZ1omZT0xNDQ0NzExMDE5JnQ9MTQ0NDcwNzQxOSZyPTEzMDMyMDgzOTAmdT0wJmY9.No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

 

分析:

Access control allow origin直譯過來就是"訪問控制允許同源",這是由於ajax跨域訪問引起的。所謂跨域就是,在a.com域下,訪問b.com域下的資源;出於安全的考慮,瀏覽器允許跨域寫,而不允許跨域讀寫就是上行,發送請求,send request,讀就是下行,接受響應,receive response;理解了這兩條規則,以下現象我們也就能理解了;

 

1、表單默認提交(get、post)、超鏈接訪問域外的資源,這是允許的,因為在點擊按鈕/超鏈接時,瀏覽器地址已經變了,這就是一個普通的請求,不存在跨域;

2、ajax(借助xmlhttprequest)跨域請求,這是被禁止的,因為ajax就是為了接受接受響應,這違背了,不允許跨域讀的原則

3、jsonp屬於跨域讀且形式限制為GET方式,它利用了script標簽的特性;這是允許的。因為瀏覽器把跨域讀腳本,當作例外,類似的img、iframe的src都可以請求域外資源

 

解決方案:

方案1,給chrome瀏覽器添加參數,--disable-web-security

 

方案2

a,

非IE瀏覽器,利用xmlhttprequest,在request header添加origin:本域名地址,通常不需要手動添加,瀏覽器會動添加

IE瀏覽器,利用XDomainRequest發送請求,它會自動封裝header中添加origin

b,response header添加access-control-allow-origin:*

 

跨域演示及代碼

驗證過程,首先訪問http://本機ip:port/project_name/a.jsp,然后,a.jsp發送ajax請求,http://localhost:port/project_name/b.jsp,這樣就產生了跨域的問題。

a.jsp

 

[html]  view plain  copy
 
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">  
  4. <head>  
  5. <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>  
  6. <title>跨域演示</title>  
  7. <script type="text/javascript" src="jquery-1.11.2.js"></script>  
  8. <script type="text/javascript" src="jquery.form.js"></script>  
  9. </head>  
  10.   
  11. <script type="text/javascript">  
  12. $(document).ready(function() {  
  13.       
  14.     $.getJSON('http://localhost/test_maven/b.jsp', function(data) {  
  15.         alert("request succeed");  
  16.     });  
  17. });  
  18. </script>  
  19. </body>  

 

 

b.jsp

[html]  view plain  copy
 
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <%  
  4.   
  5. response.setHeader("Access-Control-Allow-Origin", "*");  
  6. response.getWriter().write("hahahhaha");  
  7. %>  

 

如果注釋掉response.setHeader("Access-Control-Allow-Origin", "*");,那么就會出現access control allow origin錯誤;使用通配符*,允許所有跨域訪問,所以跨域訪問成功

但是,請注意使用通配符*,會允許來自任意域的跨域請求訪問成功,這是比較危險的,所以在生產環境通常會做更精確控制;

 

簡單請求

上述請求是簡單請求,只要添加了Access-Control-Allow-Origin:*,就會訪問成功,如果是復雜請求,我們需要更進一步的處理,才能成功。這里先解釋一下什么是簡單請求和復雜請求。

 

[html]  view plain  copy
 
  1. Simple requests  
  2.   
  3. A simple cross-site request is one that meets all the following conditions:  
  4.   
  5. The only allowed methods are:  
  6. GET  
  7. HEAD  
  8. POST  
  9. Apart from the headers set automatically by the user agent (e.g. Connection, User-Agent, etc.), the only headers which are allowed to be manually set are:  
  10. Accept  
  11. Accept-Language  
  12. Content-Language  
  13. Content-Type  
  14. The only allowed values for the Content-Type header are:  
  15. application/x-www-form-urlencoded  
  16. multipart/form-data  
  17. text/plain  

 

 

簡單來說,符合上述條件的都是“簡單請求”,除了簡單請求就是“復雜請求”。

 

 

復雜請求

在正式post之前,瀏覽器會先發出一個options請求(也叫preflight),同時header帶上origin還有Access-Control-Request-*:**之類的頭,服務器響應會返回相應的access-control-allow-origin,如果匹配,那么瀏覽器就會發送正式post,否則就會出現上述錯誤。這也解答了,跨域訪問時,我們明明發送的post請求,失敗的話,查看chrome network會發現是options方法的原因。

根據上述過程,后台方法額外需要options方法,以下是測試樣例。

這里的content-type不屬於(application/x-www-form-urlencoded,multipart/form-data,text/plain)中的任何一種,所以是復雜請求。

 

 

[html]  view plain  copy
 
  1. $.ajax({  
  2.          
  3.           type: "post",  
  4.           url: "http://localhost/test_maven/a_action",  
  5.           contentType: "application/json",  
  6.           dataType:  "json",  
  7.           success: function(){  
  8.             alert("request succeed");  
  9.         }  
  10.       });  



 

 

[html]  view plain  copy
 
  1. @RequestMapping(value = "/a_action",  
  2.         method=RequestMethod.OPTIONS)  
  3. public void aActionOption(HttpServletResponse response ) throws IOException{  
  4.       
  5.     System.out.println("option execute.....");  
  6.     response.setHeader("Access-Control-Allow-Headers", "accept, content-type");  
  7.     response.setHeader("Access-Control-Allow-Method", "POST");  
  8.     response.setHeader("Access-Control-Allow-Origin", "http://192.168.8.36");  
  9. }  

 

[html]  view plain  copy
 
  1. @RequestMapping(value = "/a_action",method=RequestMethod.POST)  
  2.     public void aAction(HttpServletResponse response ) throws IOException{  
  3.           
  4.         System.out.println("a_action execute.....");  
  5.     }  


第一次是options請求,http options請求跟get、post、head等一樣,都屬於http的請求方法,options方法,用來獲取服務器端某url支持的方法,response header中allow標志支持的方法

 

 

第二次才是真正的請求

 

 

這個方案是利用了w3c的最新規范,所以該方案依賴瀏覽器的實現。

 

總結:

出現Access control allow origin錯誤,說明是跨域請求失敗!瀏覽器發送請求成功,同時瀏覽器也接收到響應了,但是限制了XmlHttpRquest接收請求,不會讓xmlhttprequest接受到響應,並且在js控制台報錯。這也就是我們在網絡控制台(Network)能看見http 狀態碼是200,但是在js控制台(Console)出現js錯誤的原因。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM