一. 什么是跨域问题?

  • 产生的原因

    首先要知道,浏览器安全的基石是"同源政策"(same-origin policy),最初是由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

  • 如果是非同源,限制范围:

    (1) Cookie、LocalStorage 和 IndexDB 无法读取。

    (2) DOM 无法获得。

    (3) AJAX 请求不能发送。

  • 同源策略举例

    URL 说明 是否允许通信 / 是否同源
    http://www.a.com/a.js
    http://www.a.com/b.js
    同一域名下 允许
    http://www.a.com/lab/a.js
    http://www.a.com/script/b.js
    同一域名下不同文件夹 允许
    http://www.a.com:8000/a.js
    http://www.a.com/b.js
    同一域名,不同端口 不允许
    http://www.a.com/a.js
    https://www.a.com/b.js
    同一域名,不同协议 不允许
    http://www.a.com/a.js
    http://70.32.92.74/b.js
    域名和域名对应ip 不允许
    http://www.a.com/a.js
    http://script.a.com/b.js
    主域相同,子域不同 不允许
    http://www.a.com/a.js
    http://a.com/b.js
    同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
    http://www.cnblogs.com/a.js
    http://www.a.com/b.js
    不同域名 不允许
  • 为什么前后端分离开发会遇到跨域问题?

    例如后端服务运行在8080端口上,前端服务运行在63343端口上,由于端口号不同,前端在请求后端资源时会被游览器判定为跨域请求(非同源),请求会被拦截,且游览器控制台报错信息如下

    Access To XMLHttpRequest at ... from orgin ... has been blocked by CORS policy ...

    那么在开发时如何关闭游览器的同源策略?

    Mac系统下开启Chrome游览器跨域请求方法

    在终端执行以下命令即可,其中username为电脑用户名

    1
    open -n /Applications/Google\ Chrome.app/ --args --disable-web-security  --user-data-dir=/Users/username/Documents/MyChromeDevUserData

    Win系统下开启Chrome游览器跨域请求方法

    点击查看

  • 如果是在部署项目至服务器时,可使用Nginx来解决

二. 使用Nginx反向代理解决跨域问题

  • 原理举例:Nginx服务器监听指定端口号,将其指定URL请求代理至后端服务器,这样可以实现所有资源都在同一个端口号上进行访问,以下是配置方法

  • 首先打开nginx.conf配置文件(若linux默认安装完不知道在哪可执行whereis nginx命令)

    在http包裹下添加server配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    server {
    #监听端口号8085
    listen 8085;

    #配置服务请求名,若有多个用空格隔开,如 server_name www.baidu.com baidu.com test.baidu.com
    server_name 39.106.196.52;

    #编码
    charset utf-8;

    #access_log logs/host.access.log main;

    location / {

    #配置前端文件根目录
    root /data/git/projects/blog/reportApplication;

    #输入网址(server_name:port)后,默认的访问页面
    index index.html index.htm;
    }

    #反向代理
    location /api/ {

    #后端服务器API地址
    proxy_pass http://39.106.196.52:8080/reportDemo/;

    #将cookie作用域转换至对应URL,若不设置此项会导致cookie session在反向代理中丢失问题
    proxy_cookie_path /reportDemo /api;
    proxy_cookie_path /reportDemo /;

    tcp_nodelay on;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    }

    现在来分析下以上配置文件,首先这是个前后端分离项目:

    后端服务所在地址: http://39.106.196.52:8080/reportDemo/

    前端页面默认地址: http://39.106.196.52:8085/index.html

    由于端口号不同,使用Nginx反向代理,将http://39.106.196.52:8085/api/代理到后端服务,那么前端请求后端时使用这个URL,就能在8085端口上访问到8080端口资源,给游览器造成这是同源的假象。

    当然要注意cookie和session在反向代理中丢失的问题,曾在部署时遇到,最后发现要将cookie也同时代理过去,参照上面的设置即可。

三. 基于location配置多个前端项目

在上线测试时,如果为每个前端项目都配置一个域名或者端口,有点浪费资源。

因此我们希望通过IP访问加不同路径的形式来访问不同的前端项目,配置如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 这种方式配置的话,location / 目录是root,其他的要使用alias
server {
listen 80;

location / {
root /data/web-a/dist;
index index.html;
}

location /web-b {
alias /data/web-b/dist;
index index.html;
}
}

然后通过访问 IP 或 IP/web-b 就能分别访问两个不同的前端项目了。