Nginx 反向代理完全入门:从一个真实场景开始

Nginx 反向代理完全入门:从一个真实场景开始

在服务部署中,经常会遇到这样的场景:

一个在本地 8080 端口启动的服务(例如 Spring Boot 应用或 Node.js API),需要通过 https://mydomain.com/api 这样的公共地址对外提供访问。

这便是 反向代理 的典型应用场景。Nginx 作为网关,负责接收所有用户的请求,然后根据预设规则,将请求转发给内部的实际服务。

本文将介绍如何一步步搭建一个健壮的反向代理,并详细解释其中最关键的两个知识点:proxy_pass 的斜杠规则请求头的正确传递


第一步:实现基础代理

首先解决上面提出的问题。目标是:当用户访问 .../api/... 时,Nginx 将请求转发给 http://127.0.0.1:8080

在 Nginx 配置文件 server 块中,加入以下 location 配置:

nginx 复制代码
location /api/ {
    # 将请求转发给本地的 8080 端口
    proxy_pass http://127.0.0.1:8080/;
}

重启 Nginx 后,访问 https://mydomain.com/api/users,Nginx 会返回 http://127.0.0.1:8080/users 的内容。至此,最核心的代理功能已经完成。

第二步:理解 proxy_pass 的斜杠规则

proxy_pass 指令后的斜杠 / 是一个关键细节,它决定了 Nginx 如何处理和转发 URL。

以访问 https://mydomain.com/api/users 为例进行说明。

情况一:proxy_pass 带斜杠(常用)

这是刚才使用的配置:
proxy_pass http://127.0.0.1:8080/; (结尾有 /)

  • 行为 :当 proxy_pass 的地址以 / 结尾时,Nginx 会将 location 匹配到的路径从原始请求 URI 中移除,然后将剩余部分拼接到 proxy_pass 的地址后面。
  • 转换过程
    • 原始请求路径: /api/users
    • Nginx 移除匹配的 /api/,剩下: users
    • 最终后端收到的路径: /users
  • 适用场景 :这是最常见的用法。后端服务(如 Spring Boot)的路由通常从根路径 / 开始(例如 /users, /products),并不知道外部代理为其添加了 /api 前缀。

情况二:proxy_pass 不带斜杠

如果去掉结尾的斜杠:
proxy_pass http://127.0.0.1:8080; (结尾没有 /)

  • 行为 :Nginx 会将完整的原始请求 URI 直接拼接到 proxy_pass 的地址后面。
  • 转换过程
    • 原始请求路径: /api/users
    • 最终后端收到的路径: /api/users
  • 适用场景 :当后端服务本身已经配置了 /api 这个前缀(Context Path)时使用。

小结与速查

配置方式 proxy_pass 结尾 原始 URL 后端收到的路径 行为描述
方式 A http://ip:port/ (有斜杠) /api/users /users 切除前缀 (常用)
方式 B http://ip:port (无斜杠) /api/users /api/users 保留前缀 (透传)
方式 C http://ip:port/v1/ /api/users /v1/users 替换前缀

第三步:传递真实的请求头信息 proxy_set_header

经过反向代理后,后端服务直接感知到的请求方是 Nginx 服务器,而不是原始客户端。这会导致后端服务丢失关于真实用户和原始请求的关键信息。

proxy_set_header 指令可以将原始请求的重要信息添加到转发给后端的请求头中。

以下是推荐在多数场景下使用的标准配置:

nginx 复制代码
location /api/ {
    proxy_pass http://127.0.0.1:8080/;

    # === 核心 Header 传递 ===
    # 1. 传递客户端请求的域名
    proxy_set_header Host $host;

    # 2. 传递客户端的真实 IP
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 3. 传递客户端使用的协议 (http/https)
    proxy_set_header X-Forwarded-Proto $scheme;
}

Header 的作用

  1. Host $host; : 传递客户端请求的原始域名。如果后端服务需要根据域名进行逻辑判断(如多站点部署),此值至关重要。若不设置,后端获取到的 Host 可能是 127.0.0.1:8080

  2. X-Real-IPX-Forwarded-For: 传递客户端的真实 IP 地址。

    • $remote_addr 是直接连接到 Nginx 的客户端 IP。
    • $proxy_add_x_forwarded_for 会记录请求经过的每一层代理的 IP 链条,格式为 用户IP, CDN节点IP, ...
    • 若不设置,后端日志记录的访问 IP 将永远是 Nginx 服务器的 IP,这对日志分析和安全审计非常不利。
  3. X-Forwarded-Proto $scheme : 传递客户端使用的协议(httphttps)。

    • 场景 :Nginx 对外提供 https 服务,但 Nginx 与后端之间通过 http 通信以提高性能。
    • 如果后端不知道客户端正在使用 https,在执行重定向(如登录后跳转)时,可能会生成一个 http:// 链接。这会导致浏览器报告"混合内容"错误,或将用户从安全的 https 页面降级到不安全的 http 页面。

第四步:解决常见的静态资源 404 问题

一个常见的问题是:代理配置完成后,主页的 HTML 内容成功加载,但页面样式、图片等静态资源无法加载,浏览器控制台报告大量 404 错误。

问题根源

该问题通常源于应用代码中资源路径的写法

假设后端返回的 HTML 中包含以下 CSS 引用:
<link rel="stylesheet" href="/css/style.css">

这是一个根路径。浏览器会据此发起一个独立的请求,地址为:
https://mydomain.com/css/style.css

由于 Nginx 配置中只有 /api/ 路径的代理规则,没有匹配 /css/ 的规则,因此这个请求无法被正确处理,导致 404 错误。

解决方案(推荐)

最佳实践是配置应用,使其感知到自身运行在特定的子路径下。

  • 前端应用 (Vue/React) :在打包配置中设置 publicPathbase。例如,在 vue.config.js 中设置为 publicPath: '/api/'
  • 后端应用 (Spring Boot) :在 application.properties 中配置 server.servlet.context-path=/api
  • 后端应用 (Swagger UI) :需要配置相关的路径参数,使其知道基础路径是 /api

修改后,应用生成的 HTML 资源路径会自动带上 /api 前缀,变为:
<link rel="stylesheet" href="/api/css/style.css">

这样,浏览器请求的 https://mydomain.com/api/css/style.css 就能被 location /api/ 规则正确捕获并代理到后端。


完整的代理配置示例

综合以上所有知识点,一个健壮、通用的反向代理配置如下:

nginx 复制代码
# ----------------------------------------------------
# API 子路径代理
# 访问入口: https://mydomain.com/api/
# ----------------------------------------------------
location /api/ {
    # 1. 代理规则 (切掉 /api/ 前缀)
    proxy_pass http://127.0.0.1:8080/;

    # 2. 传递核心 Header
    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;

    # 3. WebSocket 支持 (可选,如果后端需要)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 4. 超时设置 (可选,如果接口耗时较长建议调大)
    proxy_connect_timeout 60s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;

    # 5. 自动修正后端重定向地址 (可选,但推荐)
    # 如果后端返回一个重定向到 /login,Nginx 会自动修正为 /api/login
    proxy_redirect default; 
}

希望这篇教程能帮助读者更好地理解和应用 Nginx 反向代理。

相关推荐
weixin_440730504 小时前
Nginx、Apache和tomcat的简单了解。
nginx·tomcat·apache
bkspiderx4 小时前
用Nginx解决HTTP跨域问题:两种实用方案详解
nginx·http·跨域·http跨域
石像鬼₧魂石4 小时前
Fail2ban + Nginx/Apache 防 Web 暴力破解配置清单
前端·nginx·apache
苹果醋318 小时前
iview— Select— Option选中后有空格
运维·vue.js·spring boot·nginx·课程设计
catoop1 天前
网站安全加固:优化 Nginx 安全头配置
nginx·安全
GRsln1 天前
解决微信小程序报“errno“:600001 ERR_CERT_AUTHORITY_INVALID问题
nginx·微信小程序·小程序·ssl
艾德金的溪1 天前
性能数据接收接口I/O堵塞问题处理及Nginx分流扩容方案
nginx
奔跑吧邓邓子1 天前
从0到1:SSH安全连接配置全攻略
ssh·配置·安全连接·全攻略
iru2 天前
nginx被报CVE-2025-1695漏洞,检查后反馈是误报
运维·nginx