引言
前置知识:跨源资源共享(CORS)
在本地进行前后端开发,经常会遇见跨域问题,对于新手来说可能比较头疼。
本文主要讨论,如何使用nginx反向代理,来解决跨域问题。
代码准备
gitlab仓库地址:https://lab.co.link/study/cors-demo 。
或参照以下内容,创建代码文件。
前端网页代码
创建index.html
,复制以下内容。
<html>
<head>
<title>CORS Demo</title>
<script>
const SERVER_ADDR = "http://127.0.0.1:8000/api/health";
function request() {
fetch(SERVER_ADDR).then((res) => {
console.log(res);
});
}
</script>
</head>
<body>
<button onclick="request();">Request</button>
</body>
</html>
后端服务代码
创建server.js
,复制以下内容。
const http = require('http');
const server = http.createServer();
server.on('request', function (request, response) {
console.log('get request: ', request.method, request.url);
response.end("ok");
});
server.listen(8000);
console.log("server running...");
nginx配置文件
创建nginx.conf
,复制以下内容。
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/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 /var/log/nginx/access.log main;
server {
listen 8080;
# backend-addr
location /api/ {
proxy_pass http://host.docker.internal:8000;
}
# frontend-addr
location / {
proxy_pass http://host.docker.internal:5500;
}
}
}
问题场景重现
启动前端服务
为便于演示,使用vscode的Live Server扩展,启动前端网页服务,服务地址是http://127.0.0.1:5500 (根据个人vscode本地配置,地址可能有所不同)。
也可使用其他自己偏好的方式启动前端网页服务。
前端服务地址不一致的,需自行更新本文涉及到的前端服务地址。
启动后端服务
执行node server.js
,启动后端服务,服务地址是http://127.0.0.1:8000。
问题重现
打开浏览器控制台,然后点击Request按钮,发现控制台出现跨域报错。
原因是运行在http://127.0.0.1:5500 的JS代码,发起了到http://127.0.0.1:8000 的请求,两者属于不同域,是跨域请求;而后端服务器又没有配置允许跨域。
解决方案
在后端服务器配置允许跨域,如nodejs经常会使用到的cors依赖。
使用nginx进行反向代理,使前端服务与后端服务处于同一域。
鉴于大家使用的语言及web框架都比较丰富,部分框架不支持配置允许跨域,故本文主要介绍第二种方案:nginx反向代理。
nginx反向代理
安装运行nginx
1. 使用docker安装nginx
推荐使用docker安装nginx,可以保证大家使用到一样的程序环境。
a. 先搜索下载安装docker,随后根据后文操作。
b. 安装好docker后,于项目目录下,执行以下命令。
# 检查docker是否成功安装
docker -v
# 拉取docker镜像
docker pull nginx:1.22
# 创建并运行nginx容器
docker run --name my-nginx -d -p 8080:8080 nginx:1.22
# 复制nginx配置文件至容器内
docker cp nginx.conf my-nginx:/etc/nginx/nginx.conf
# 重启nginx容器
docker restart my-nginx
# 在对配置文件进行更新后,执行后两条命令即可生效(复制配置及重启容器)
扩展知识:Docker 入门教程
2. 在主机直接安装nginx
a. 根据主机系统,在网上搜索安装教程即可。
b. 安装成功后可执行nginx -h
,查看默认的配置文件地址。
将以下内容复制到配置文件的http模块内
server {
listen 8080;
# backend-addr
location /api/ {
proxy_pass http://127.0.0.1:8000;
}
# frontend-addr
location / {
proxy_pass http://127.0.0.1:5500;
}
}
c. 执行nginx
启动服务。
d. 在对配置文件进行更新后,执行nginx -s reload
即可生效。
测试nginx效果
a. 将index.html里的SERVER_ADDR值,更新为http://127.0.0.1:8080/api/health
。
b. 打开地址http://127.0.0.1:8080 ,可正常显示前端网页内容。
c. 点击Request,没有再出现跨域报错,正常获取到请求结果。
d. 使用vscode的Live Server插件启动前端服务的同学,控制台可能会出现Websocket报错,原因是Live Server热加载的ws连接没有配置代理。
有需要的可以在配置文件server模块中再添加以下语句。
# frontend live reloading
location ~ /ws$ {
proxy_pass http://host.docker.internal:5500;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
至此,成功使用nginx解决跨域问题。