AJAX跨域问题[CROS与NIGNX]以及cookie跨域共享

本地跨域与服务器跨域

前端页面与后台运行在不同的服务器或不同的域名时,就会出现跨域问题。

本地跨域:

如果是同一台服务器,前后端url拥有不同的域名,则通过后端设置正确的请求体origin则可解决:
(为了安全起见,前端不得修改请求体的 Origin域名)

     //定义响应头信息
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Allow-Headers: Content-Type, Origin, X-Requested-With, Accept');
        header('Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS');
        header('Access-Control-Max-Age: 3600');
        header('Access-Control-Allow-Origin:' . '前端域名网址');

服务器跨域:

目前解决这类跨域问题主要有以下方法:
不讨论只能使用GET的jsonp方法。

方法一、CROS(跨域资源共享,Cross-Origin Resource Sharing)的方法。

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)跨域资源共享 CORS 详解。看名字就知道这是处理跨域问题的标准做法。CORS有两种请求,简单请求和非简单请求。

简单请求下, 可以使用:

header("Access-Control-Allow-Origin", "*"); //表示允许任何远程访问
设置Access-Control-Allow-Methods //允许访问的方法等

非简单请求:

如果发送的是带凭据的非简单请求,但服务器的相应中没有包含这个头部,那么浏览器就不会把相应交给JavaScript,请求就无法得到结果的数据(浏览器得到了,但是我们请求的方法得不到,因为被浏览器拦截了),因此在withCredentials时,服务端的Access-Control-Allow-Origin必须配置具体的具体的域名, 不能为通配符。并且还需要设置其他的请求头:

CROS协议流程

1、设置HTTP响应头Access-Control-Allow-Origin,指定服务器端允许进行跨域资源访问的来源域。

2、预请求验证:
浏览器在发现页面中有上述条件的动态跨域请求的时候,并不会立即执行对应的请求代码,而是会先发送Preflighted requests(预先验证请求)

OPTIONS请求头部中会包含以下头部:Origin、Access-Control-Request-Method、Access-Control-Request-Headers。
服务器收到OPTIONS请求后,设置Access-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers头部与浏览器沟通来判断是否允许这个请求。

3、服务端流程[重要]
要实现CORS跨域,服务端需要这个一个流程:服务端流程
流程如下:

首先查看http头部有无origin字段;
如果没有,或者不允许,直接当成普通请求处理,结束;
如果有并且是允许的,那么再看是否是preflight(method=OPTIONS);
如果是preflight,就返回Allow-Headers、Allow-Methods等,内容为空;
如果不是preflight,就返回Allow-Origin、Allow-Credentials等,并返回正常内容。
服务端响应流程配置, 参考以下在过滤器中间层中处理的配置:

        header('Access-Control-Allow-Credentials: true'); // 非简单请求下的配置处理
       header('Access-Control-Allow-Headers: Origin, Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');
        header('Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS');
        header('Access-Control-Max-Age: 3600');
        header('Access-Control-Allow-Origin: ' . Request::instance()->header('Origin'));
        //非简单请求下, 指定获取到的单个域名[间接通配], 此处加白名单组校验更好。
对于预请求的处理可以有以下几种方法:

1、JAVA的拦截器或者PHP中入口文件对OPTIONS请求进行拦截return

2、NIGNX在流程中统一处理

NIGNX对以上流程实现以及OPTIONS请求处理配置:参考

下面nginx-spdy-push里/pub接口启用CORS的配置:

location ~ ^/pub/([-_.A-Za-z0-9]+)$ {
 
    set $cors "local";
 
    # configure CORS based on https://gist.github.com/alexjs/4165271
    # (See: http://www.w3.org/TR/2013/CR-cors-20130129/#access-control-allow-origin-response-header )
 
    if ( $http_origin ~* "https://.+\.gw\.com\.cn(?=:[0-9]+)?" ) {
        set $cors "allow";
    }
    if ($request_method = "OPTIONS") {
        set $cors "${cors}options";
    }
 
    # if CORS request is not a simple method
    if ($cors = "allowoptions") {
        # Tells the browser this origin may make cross-origin requests
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        # in a preflight response, tells browser the subsequent actual request can include user credentials (e.g., cookies)
        add_header 'Access-Control-Allow-Credentials' "true";
 
        # === Return special preflight info ===
 
        # Tell browser to cache this pre-flight info for 1 day
        add_header 'Access-Control-Max-Age' 86400;
 
        # Tell browser we respond to GET,POST,OPTIONS in normal CORS requests.
        # Not officially needed but still included to help non-conforming browsers.
        # OPTIONS should not be needed here, since the field is used
        # to indicate methods allowed for 'actual request' not the preflight request.
        # GET,POST also should not be needed, since the 'simple methods' GET,POST,HEAD are included by default.
        # We should only need this header for non-simple requests  methods (e.g., DELETE), or custom request methods (e.g., XMODIFY)
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
 
        # Tell browser we accept these headers in the actual request
        add_header 'Access-Control-Allow-Headers' 'reqid, nid, host, x-real-ip, x-forwarded-ip, event-type, event-id, accept, content-type';
 
        # === response for OPTIONS method ===
 
        # no body in this response
        add_header 'Content-Length' 0;
        # (should not be necessary, but included for non-conforming browsers)
        add_header 'Content-Type' 'text/plain, charset=utf-8';
        # indicate successful return with no content
        return 204;
    }
 
    if ($cors = "allow") {
        rewrite /pub/(.*) /pub_cors/$1 last;
    }
 
    if ($cors = "local") {
        rewrite /pub/(.*) /pub_int/$1 last;
    }
}
 
location ~ /pub_cors/(.*) {
    internal;
    # Tells the browser this origin may make cross-origin requests
    add_header 'Access-Control-Allow-Origin' "$http_origin";
    # in a preflight response, tells browser the subsequent actual request can include user credentials (e.g., cookies)
    add_header 'Access-Control-Allow-Credentials' "true";
 
    push_stream_publisher                   admin; # enable delete channel
    set $push_stream_channel_id             $1;
 
    push_stream_store_messages              on;  # enable /sub/ch.b3
    push_stream_channel_info_on_publish     on;
}
 
location ~ /pub_int/(.*) {
  #  internal;
    push_stream_publisher                   admin; # enable delete channel
    set $push_stream_channel_id             $1;
 
    push_stream_store_messages              on;  # enable /sub/ch.b3
    push_stream_channel_info_on_publish     on;
}

方法二、NIGNX反向代理解决跨域:

[CORS] 需要服务器设置header :Access-Control-Allow-Origin。客户端AJAX额外携带参数,而
NIGNX反向这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。

nginx配置

关于nginx的配置可以查看另一篇博文:http://www.cnblogs.com/renjing/p/6126284.html。找到nginx的配置文件“nginx.conf”,修改一下信息

server {
        listen       80; #监听80端口,可以改成其他端口
        server_name  localhost; # 当前服务的域名

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass http://localhost:81;
            proxy_redirect default;
        }

        location /apis { #添加访问目录为/apis的代理配置
            rewrite  ^/apis/(.*)$ /$1 break;
            proxy_pass   http://localhost:82;
       }
#以下配置省略

配置解释:

1.由配置信息可知,我们让nginx监听localhost的80端口,网站A与网站B的访问都是经过localhost的80端口进行访问。
2.我们特殊配置了一个“/apis”目录的访问,并且对url执行了重写,最后使以“/apis”开头的地址都转到“http://localhost:82”进行处理。
3.rewrite ^/apis/(.)1 break;
代表重写拦截进来的请求,并且只能对域名后边以“/apis”开头的起作用,例如www.a.com/apis/msg?x=1重写。只对/apis重写。
  rewrite后面的参数是一个简单的正则 ^/apis/(.
)1代表正则中的第一个(),$2代表第二个()的值,以此类推。
  break代表匹配一个之后停止匹配。
4.经过重写后的请求,都会被认为是同源请求,从而不会导致跨域问题。
—————————————————————————————————————

cookie共享设置

一、将cookie的domain设置为多个/共同的顶级域名


AJAX跨域问题[CROS与NIGNX]以及cookie跨域共享_第1张图片
图片.png

二、带认证的请求
默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。
在ajax里带上参数:
1 crossDomain: true,
2 xhrFields:{
3 withCredentials:true
4 },
如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。
在服务端设置:
Access-Control-Allow-Credentials: true
服务器还可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求。

你可能感兴趣的:(AJAX跨域问题[CROS与NIGNX]以及cookie跨域共享)