Nginx反向代理是解决前后端分离跨域最推荐的方式:前端请求同源/api/路径,Nginx将其转发至Node.js服务并透传真实请求头,浏览器无跨域感知;配置需注意proxy_pass末尾斜杠、X-Forwarded-*头及OPTIONS预检处理。

用 Nginx 代理 Node.js 后端,是解决前后端分离跨域最干净、最推荐的方式——不改一行后端代码,也不依赖框架中间件,所有跨域逻辑集中在入口层统一管控。
核心思路:用反向代理抹平“跨域感”
前端(比如 https://www.php.cn/link/c5e212421256cf0dcf335940944bc162)直接请求自己的域名,Nginx 把带 /api/ 的路径悄悄转发给 Node.js 服务(比如 http://127.0.0.1:3000),浏览器全程只看到一个源,根本不会触发 CORS 预检。这是最本质的解法,比加响应头更彻底。
- 前端发请求:
GET https://www.php.cn/link/c5e212421256cf0dcf335940944bc162/api/users - Nginx 拦截该请求,内部转发到:
GET http://127.0.0.1:3000/users - 响应返回时,仍是
https://www.php.cn/link/c5e212421256cf0dcf335940944bc162域名下的响应,无跨域
Nginx 配置示例(含关键细节)
在 server 块中添加如下配置:
location /api/ {
proxy_pass http://127.0.0.1:3000/; # 注意末尾斜杠:保留路径重写逻辑
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
<pre class="brush:php;toolbar:false;"># 若 Node.js 服务需读取原始 Host 或协议,这三行很关键
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";}
说明:
-
proxy_pass末尾的/是重点:它让/api/users转发为/users,避免后端收到带/api前缀的路径 - 如果 Node.js 使用 Express/Koa,通常监听
/users,而非/api/users,所以这个 rewrite 是隐式完成的 -
X-Forwarded-*头让 Node.js 能正确获取用户真实 IP 和协议(尤其启用 HTTPS 时)
需要显式配 CORS 的场景(补充方案)
极少数情况,比如前端要直连 Node.js(不走 Nginx 代理)、或调试阶段临时允许外部域名访问,才需在 Nginx 中加 CORS 响应头:
add_header 'Access-Control-Allow-Origin' 'https://www.php.cn/link/c5e212421256cf0dcf335940944bc162';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Accept,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Expose-Headers' 'Content-Length, X-Total-Count';
<h1>必须处理预检请求(OPTIONS)</h1><p>if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '<a href="https://www.php.cn/link/c5e212421256cf0dcf335940944bc162">https://www.php.cn/link/c5e212421256cf0dcf335940944bc162</a>';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Accept,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}</p>
注意:
- 不要用
*配合Access-Control-Allow-Credentials true,会失效;必须指定明确域名 - 务必拦截并响应
OPTIONS请求,否则浏览器预检失败,后续请求直接被拦 -
Access-Control-Expose-Headers可选,但若前端需读取自定义响应头(如分页总数),就得列出来
Node.js 端可保持简洁
此时 Node.js 应专注业务,无需引入 cors 中间件或手动设 header。若仍想留一层防护,仅需最小化配置:
// Express 示例(非必需,仅作兜底)
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://www.php.cn/link/c5e212421256cf0dcf335940944bc162');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
真正上线后,建议完全移除这类代码,让 Nginx 全权负责跨域治理,职责清晰、性能更高、维护更简单。











