跨域解决方案

936 阅读2分钟

jsonp

该方案非常简单,就此略过

跨域资源共享(cors)

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

前端设置

// jQuery 1.5.1 xhrFields: {withCredentials: true}
// ES6 fetch() credentials: 'include'
// axios: withCredentials: true

withCredentials: true,
crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie

服务端设置

  1. node
// 跨域后台设置
res.writeHead(200, {
    'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
    'Access-Control-Allow-Origin': 'http://www.domain1.com',    // 允许访问的域(协议+域名+端口)
    /* 
     * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
     * 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
     */
    'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
});
  1. java
/*
 * 导入包:import javax.servlet.http.HttpServletResponse;
 * 接口参数中定义:HttpServletResponse response
 */

// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 

// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 

// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");

nginx设置允许跨域请求头

  1. 不需要cookie的情况下,只需设置Access-Control-Allow-Origin : *即可
  2. 如果需要cookie的话
location / {
    if ($http_origin ~ [a-z]+\.hearu\.top$){ # xxx.hearu.top域名才可以访问
        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Request-Method GET;
        add_header Access-Control-Allow-Credentials true;
    }
    root /usr/local/...../ui; #存放静态文件的路径
    #expires 1h;
}

nginx if 指令参考: 连接

正则表达式匹配:

  • ==:等值比较;
  • ~:与指定正则表达式模式匹配时返回“真”,区分字符大小写;
  • ~*:与指定正则表达式模式匹配时返回“真”,不区分字符大小写;
  • !~:与指定正则表达式模式不匹配时返回“真”,区分字符大小写;
  • !~*:与指定正则表达式模式不匹配时返回“真”,不区分字符大小写;

文件及目录匹配判断:

  • -f, !-f:判断指定的路径是否为存在且为文件;
  • -d, !-d:判断指定的路径是否为存在且为目录;
  • -e, !-e:判断指定的路径是否存在,文件或目录均可;
  • -x, !-x:判断指定路径的文件是否存在且可执行;

nginx 反向代理

即然说到nginx反向代理,那就也来说说正向代理

  1. 正向代理就是我们访问不了Google,但是我在国外有一台vps,它可以访问Google,我访问它,叫它访问Google后,把数据传给我。

2. 反向代理 大家都有过这样的经历,拨打10086客服电话,可能一个地区的10086客服有几个或者几十个,你永远都不需要关心在电话那头的是哪一个,叫什么,男的,还是女的,漂亮的还是帅气的,你都不关心,你关心的是你的问题能不能得到专业的解答,你只需要拨通了10086的总机号码,电话那头总会有人会回答你,只是有时慢有时快而已。那么这里的10086总机号码就是我们说的反向代理。客户不知道真正提供服务人的是谁。

反向代理隐藏了真实的服务端,当我们请求 www.baidu.com 的时候,就像拨打10086一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器,用来做负载均衡。

总结:正向代理隐藏了真实的客户端。反向代理隐藏了真实的服务器。

url重写

如果想将/api下的url反向代理到后端,可以通过在nginx.conf中配置url重写规则如下:

location / {
    root   html;
    index  index.html index.htm;
    location ^~ /api {
        rewrite ^/api/(.*)$ /$1 break;
        proxy_pass https://www.b.com/;
    }
}

如果Cookie的域名部分与当前页面的域名不匹配就无法写入。所以如果请求 www.a.com ,服务器 proxy_pass 到 www.b.com 域名,然后 www.b.com 输出 domian=b.com 的 Cookie,前端的页面依然停留在 www.a.com 上,于是浏览器就无法将 Cookie 写入。

可在nginx反向代理中设置:

location / {
    root   html;
    index  index.html index.htm;
    location ^~ /api {
        rewrite ^/api/(.*)$ /$1 break;
        proxy_pass https://www.b.com/;
        proxy_cookie_domain b.com a.com;
    }
}