zoukankan      html  css  js  c++  java
  • Access control allow origin 简单请求和复杂请求

    原文地址:http://blog.csdn.net/wangjun5159/article/details/49096445

    错误信息:

    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错误的原因。

  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/zxtceq/p/8417606.html
Copyright © 2011-2022 走看看