zoukankan      html  css  js  c++  java
  • [转] js网络请求跨域问题汇总(携带cookie)

    前端程序使用extjs写,在本地测试,发送请求到服务器时,发现存在跨域的问题,cookie也没有set成功,于是乎在这里整理一下解决过程

    由于篇幅较长,不想看解决过程的可以翻到最后看总结
    1.跨域允许
    2.客户端无法携带跨域cookie
    3.因为加了withCredentials报文头,可是客户端不知道服务器允不允许报的错
    4.由于客户端不知道服务端是否允许POST请求而报的错

    假设我的服务器IP是120.111.111.123

    # 本地的html
    # index.html
    
    <html>
    <head>
        <meta charset="utf8">
    </head>
    <body>
        <input type="button" onclick="request()" value="请求">
    </body>
    <script type="text/javascript" src="./ext-all.js"></script>
    <script type="text/javascript">
        function request(){
            Ext.Ajax.request({
                url: 'http://120.111.111.123/setcookie.php',
                method: 'POST',
                params: { 
                    'text': 'hello world'
                },
                success: function(transport){
                    // do something
                },
                failure: function(transport){
                    alert("Error: " - transport.responseText);
                }
            });
        }
        
    </script>
    </html>
    
    #服务器的php文件
    #path setcookie.php
    <?php
    session_start();
    ?>
    

    点击“请求”按钮,发送请求后发现js报错

    XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. 
    Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 
    Origin 'null' is therefore not allowed access.
    

    报这个错就说明我们跨域了,不在允许的访问源,于是乎我在服务的setcookie.php加入header('Access-Control-Allow-Origin:*');允许所有源

    <?php
    session_start();
    header('Access-Control-Allow-Origin:*'); 
    
    // 功能...
    // ...
    

    然后又报错

    XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.
    

    这次的报错是因为,在跨域的时候,extjs不会直接发post请求,而是先发送一个option请求,看看服务器允许什么访问头(比如是不是允许post请求),验证成功后才会发送真正的请求

    #用谷歌的开发者工具抓的option报文
    OPTIONS /setcookie.php HTTP/1.1
    Host: 120.111.111.123
    Connection: keep-alive
    Pragma: no-cache
    Cache-Control: no-cache
    Access-Control-Request-Method: POST
    Origin: null
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
    Access-Control-Request-Headers: x-requested-with
    Accept: */*
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: zh-CN,zh;q=0.8
    

    接下来,我们只要发送我们允许什么请求头就行了

    #path /setcookie.php
    
    session_start();
    header('Access-Control-Allow-Origin:*'); 
    
    header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); // 允许option,get,post请求
    header('Access-Control-Allow-Headers:x-requested-with'); // 允许x-requested-with请求头
    header('Access-Control-Max-Age:86400'); // 允许访问的有效期
    
    // 功能...
    // ...
    

    继续测试我们的新功能,成功的解决了跨域问题

     
    1.png


    but,cookie没有“设置成功”。而之所以没有“设置成功”,是因为cookie存在本地,但是每个cookie都有一个domain,当你本地的cookie中存在你当前访问的域时,才会被带过去,而我的index.html文件是本地访问的,即http://localhost/index.html,而cookie的域是120.111.111.123的,所以不行了。于是乎继续改

    #path index.html
    <html>
    <head>
        <meta charset="utf8">
    </head>
    <body>
        <input type="button" onclick="request()" value="请求">
    </body>
    <script type="text/javascript" src="./ext-all.js"></script>
    <script type="text/javascript">
        function request(){
            Ext.Ajax.request({
                url: 'http://120.111.111.123/setcookie.php',
                method: 'POST',
                params: { 
                    'text': 'hello world'
                },
                withCredentials: true, # 加了这个
                success: function(transport){
                    // do something
                },
                failure: function(transport){
                    alert("Error: " - transport.responseText);
                }
            });
        }
        
    </script>
    </html>
    

    继续访问,报错

    XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. 
    Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. 
    Origin 'null' is therefore not allowed access. 
    The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
    

    现在这个错误产生的原因就是
    1.因为加入了withCredentials之后,Access-Control-Allow-Origin就不能用“*”了,既然不允许访问这个源,那我就让你发个报文头让你允许访问呗!

    <?php
    #path setcookie.php
    session_start();
    // 是否存在请求源
    if(isset($_SERVER["HTTP_ORIGIN"])) {
        header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);  
    }
    
    header('Access-Control-Allow-Methods:OPTIONS, GET, POST');
    header('Access-Control-Allow-Headers:x-requested-with');
    header('Access-Control-Max-Age:86400');
    
    // 功能...
    // ...
    
    ?>
    

    好了,上传完代码,继续测试。发送请求之后,又报错了(这错中错,一个个坑搞的大家都看得不耐烦了吧,我保证,这是最后一个报错了)

    XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. 
    Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. 
    It must be 'true' to allow credentials. Origin 'null' is therefore not allowed access.
    

    大概的意思就是说我给你发了withCredentials报文头,但是你服务器没有跟我说允许我带这个报文头,那么解决方法就是加上允许发这个报文头的报文头

    # path setcookie.php
    <?php
    
    session_start();
    // 是否存在请求源
    if(isset($_SERVER["HTTP_ORIGIN"])) {
        header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);  
    }
    header('Access-Control-Allow-Origin:null');  
    header('Access-Control-Allow-Methods:OPTIONS, GET, POST');
    header('Access-Control-Allow-Headers:x-requested-with');
    header('Access-Control-Max-Age:86400');
    
    header('Access-Control-Allow-Credentials:true');
    
    
    // 功能...
    // ...
    
    ?>
    

    接下来进行最终的测试,biu~成功了,终于成功了!!!(0.0自己嗨起来了)

     
    2.png

    接下来总结一下,之所以跨域会引起那么多问题,都是因为耿直的客户端,发什么类型的请求都要服务器允许,而且要明文允许,允许的内容包括如下
    1.跨域允许
    解决方法:服务器发送允许客户端发送源的报文头
    header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);

     
    4.png

    2.客户端无法携带跨域cookie
    这个时候就可以在extjs中加入withCredentials

           Ext.Ajax.request({
                url: 'http://120.111.111.123/setcookie.php',
                method: 'POST',
                params: { 
                    'text': 'hello world'
                },
                withCredentials: true,
                success: function(transport){
                    // do something
                },
                failure: function(transport){
                    alert("Error: " - transport.responseText);
                }
            });
    

    3.因为加了withCredentials报文头,可是客户端不知道服务器允不允许报的错(耿直的客户端)
    这个时候就在服务器发送Access-Control-Allow-Credentials

    header('Access-Control-Allow-Credentials:true');
    

    4.由于客户端不知道服务端是否允许POST请求而报的错
    这个时候要在服务器端加入

    header('Access-Control-Allow-Methods:OPTIONS, GET, POST');
    header('Access-Control-Allow-Headers:x-requested-with');
    header('Access-Control-Max-Age:86400');
    

    以上汇总起来就是

    header('Access-Control-Allow-Methods:OPTIONS, GET, POST');
    header('Access-Control-Allow-Headers:x-requested-with');
    header('Access-Control-Max-Age:86400');  
    header('Access-Control-Allow-Origin:'.$_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Credentials:true');
    header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers:x-requested-with,content-type');
    header('Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With');
    

  • 相关阅读:
    YC创始人格雷厄姆为何不喜欢大学生创业?
    在创业的道路上,让公司生存下去是做重要的!
    农村90后李传帅的创业故事
    创业公司的出头之日在哪里?
    创业者不能盲目的跟风,不然结局很凄凉
    小程序到底适不适合创业者
    共享经济的涨潮与退潮就在一瞬间
    互联网行业进入焦虑时代,如何才能做到攻守有道?
    88
    JZOJ.5331【NOIP2017模拟8.23】壕游戏
  • 原文地址:https://www.cnblogs.com/chris-oil/p/11558417.html
Copyright © 2011-2022 走看看