前言

最近遇到了跨域问题,结合之前【微信支付开发本地接收异步通知回调】的经验,利用 Nginx 实现了跨域。

公司之前为了解决跨域问题,用的是 iFrame,反正对于只做后端的我而言,觉得很复杂,但是现在利用 nginx 如此简单就实现了跨域,感觉还挺有成就感,哈哈!

为什么会出现跨域问题?

前人已经总结得很好了,就借鉴一下吧!

图片来源地址: http://www.cnblogs.com/gabrielchen/p/5066120.html

我们在开发项目中遇到的跨域问题具体是这样的,公司的域名若是 www.domain.com,那么如果是发送的 Ajax 请求就不通过这个域名走了,而是通过 a.domain.com,于是便出现了跨域问题。

比如在 www.domain.com 首页中需要通过 Ajax 获取用户登录信息。

准备工作

下载演示项目

为了演示这个跨域问题,我创建了一个 SpringBoot 项目,便于演示,如果不会 SpringBoot 也没有关系,因为重点在于 Nginx 配置上面。

【点我下载】 提取密码: 8e68

启动演示项目

因为是SpringBoot 项目,因此可以通过 java -jar 的方式直接启动,为了演示跨域,因此需要启动两个项目,这里我们用两个端口来分别启动项目。

1
2
3
4
5
## A 项目,端口设置为8080
java -jar -Dserver.port=8080 demo.jar

## B 项目,端口设置为8090
java -jar -Dserver.port=8090 demo.jar

配置本地 Host

为了演示还需要两个域名,不用真正的域名,修改本地的 Host 即可,将两个域名的 Host 都执行本地。可以使用 SwitchHosts 来方便切换。

1
2
127.0.0.1 www.domain.com
127.0.0.1 a.domain.com

配置Nginx

编译安装 Nginx后, 修改 nginx.conf 配置文件。

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#user  nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
keepalive_timeout 65;
#gzip on;

upstream webServer {
server 127.0.0.1:8080;
}
upstream ajaxServer {
server 127.0.0.1:8090;
}

server {
listen 80;
server_name a.domain.com;

location / {
proxy_pass http://ajaxServer;
}
}

server {
listen 80;
server_name www.domain.com;

location / {
proxy_pass http://webServer;
}
}
}

这里来详细解释一下这里的配置,a.domain.com 代理到 ajaxServer,即端口设置为 8090 的 B 项目;

1
2
3
4
5
6
7
8
server {
listen 80;
server_name a.domain.com;

location / {
proxy_pass http://ajaxServer;
}
}

再看看 www.domain.com 的配置,反向代理到 webServer , 即端口设置为 8080 的 A 项目。

1
2
3
4
5
6
7
8
server {
listen 80;
server_name www.domain.com;

location / {
proxy_pass http://webServer;
}
}

测试

访问项目地址 http://www.domain.com/page, 进入以下页面:

当输入框不输入或者输入的是当前域名 http://www.domain.com 时,可以正常提交,不会遇到跨域问题。

当输入 http://a.domain.com 时,点击按钮进行提交,会出现跨域问题。

修改 Nginx 配置文件

修改 www.domain.com 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name www.domain.com;

location /proxy/ {
proxy_set_header Host a.domain.com;
proxy_pass http://ajaxServer/;
}

location / {
proxy_pass http://webServer;
}
}

其中这里这处配置是这篇文章的关键点。意思是 http://www.domain.com/proxy/ 开头的请求将会被反向代理到 B 项目http://a.domain.com 域名,proxy_set_header Host 这一行是必须的。需要注意的是,这两行的域名需要保持一致,且第二行后面必须要有一个 /,至于原因,可以参考这篇文章 proxy_pass后的url加不加/的区别

1
2
3
4
location /proxy/ {
proxy_set_header Host a.domain.com;
proxy_pass http://ajaxServer/;
}

修改之后保存配置文件,重启 Nginx

1
./nginx -s reload

再次测试

修改提交 URL 为 http://www.domain.com/proxy

点击按钮进行提交,发现此时没有出现跨域问题。虽然提交的URL 域名是 http://www.domain.com,而请求经过 Nginx 的反向代理之后,实际上提交到了 B 项目,即 http://a.domain.com, 也可以看到 B 项目打印了输出语句 userId: 12,由此便解决了跨域问题。

资源下载

文章涉及的jar文件我打成一个压缩包,可以自己下载尝试一下。

【点我下载】 提取密码: 8e68