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

     

  • 相关阅读:
    (转)ASP连接sql server实例解析
    (转)ASP与sql存储过程
    将博客搬至CSDN
    详细解析Java中抽象类和接口的区别
    蔬菜销售策划
    医学学习
    mlecms v2.2版权
    网页打印设置
    silverlight RadGridView总结系列(转载)
    silverlight RadGridView总结二(转载)
  • 原文地址:https://www.cnblogs.com/Gbeniot/p/7486646.html
Copyright © 2020-2023  润新知