Nginx反向代理之域名转发与路径重写配置指南

 更新时间:2026年07月10日 08:44:48   作者:知远漫谈  
在现代互联网架构中,反向代理早已不再是可选技能,而是构建高可用、高性能、安全稳定服务的核心基石,本文将带你深入 Nginx 反向代理的进阶世界,系统性地解析域名转发与路径重写两大核心机制,需要的朋友可以参考下

引言

在现代互联网架构中,反向代理早已不再是“可选技能”,而是构建高可用、高性能、安全稳定服务的核心基石。Nginx 作为最流行的反向代理服务器之一,凭借其轻量、高效、模块化的设计,成为无数企业级应用的首选。然而,许多开发者对 Nginx 的理解仍停留在“简单转发”层面——proxy_pass http://localhost:8080; 就是全部。殊不知,真正的力量在于精准控制流量的流向与形态:如何根据域名动态路由?如何将 /api/v1/user 透明重写为 /user-service/api/v1/user?如何在不修改后端代码的前提下,实现多租户、灰度发布、API 网关式管理?

本文将带你深入 Nginx 反向代理的进阶世界,系统性地解析域名转发路径重写两大核心机制。我们将从基础语法讲起,逐步过渡到复杂场景实战,结合真实 Java 后端服务示例,展示如何通过 Nginx 实现无侵入式架构升级。你将学会如何用几行配置,让一个原本只能访问 http://app.example.com:8080 的 Spring Boot 服务,对外表现为 https://api.yourcompany.com/v1/users,同时还能自动处理负载均衡、SSL 终止、缓存策略和安全头注入。

无论你是运维工程师、后端开发者,还是全栈架构师,掌握这些技能都将极大提升你对系统流量的掌控力。准备好了吗?让我们开启这场从“能用”到“优雅”的进阶之旅

一、反向代理基础:理解 Nginx 的流量入口

在深入域名转发与路径重写之前,我们必须先厘清一个根本问题:Nginx 是如何“代理”请求的?

想象一下,你的用户通过浏览器访问 https://api.example.com/users。这个请求首先抵达的是 Nginx 服务器(监听 443 端口),而非你的 Java 应用(运行在 8080 端口)。Nginx 接收请求后,根据配置规则,决定“把这个问题交给谁处理”——可能是本地的 Tomcat,也可能是远在 AWS 的微服务集群。这个“中间人”角色,就是反向代理的本质。

1.1 最基础的 proxy_pass 配置

server {
    listen 443 ssl;
    server_name api.example.com;
    ssl_certificate /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;
    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

这段配置看似简单,实则暗藏玄机:

  • listen 443 ssl;:监听 HTTPS 请求
  • server_name api.example.com;:匹配请求头中的 Host 字段,确保只有访问该域名的请求才会被处理
  • location / { ... }:匹配所有路径(根路径)
  • proxy_pass http://localhost:8080;:将请求转发到本地 8080 端口的 Java 服务

关键点proxy_pass 后面的 URL 是否包含路径,决定了 Nginx 如何处理原始请求路径!

1.2 路径拼接陷阱:带路径 vs 不带路径

这是新手最容易踩的坑!

情况一:proxy_pass不带路径

location /api/ {
    proxy_pass http://backend:8080;  # 注意:没有尾部 /
}

请求:https://api.example.com/api/v1/users
→ Nginx 转发为:http://backend:8080/api/v1/users

行为:Nginx 将 location 匹配的部分(/api/原样保留,拼接到目标 URL 后面。

情况二:proxy_pass带路径

location /api/ {
    proxy_pass http://backend:8080/service/;  # 注意:有尾部 /
}

请求:https://api.example.com/api/v1/users
→ Nginx 转发为:http://backend:8080/service/v1/users

行为:Nginx 会移除 location 中匹配的路径部分(/api/),然后将剩余部分(v1/users)拼接到 proxy_pass 的路径之后(/service/)。

情况三:错误组合(不带 / 的 location + 带路径的 proxy_pass)

location /api {  # 没有尾部 /
    proxy_pass http://backend:8080/service/;  # 有尾部 /
}

请求:https://api.example.com/api/v1/users
→ Nginx 转发为:http://backend:8080/service/v1/users ✅(看似正常)

但请求:https://api.example.com/api(无尾部)
→ Nginx 转发为:http://backend:8080/service

问题来了:如果后端服务期望 /api 作为路径前缀,而你却在 proxy_pass 中重写了它,那么后端代码中 @RequestMapping("/api") 的路径将永远无法匹配,因为请求到达时已经变成了 /service

最佳实践

  • 如果 location/ 结尾 → proxy_pass 也以 / 结尾
  • 如果 location 不以 / 结尾 → proxy_pass 也不应带路径
  • 强烈建议:统一使用带 / 的写法,语义清晰,避免歧义

1.3 Java 后端如何感知真实请求?

Nginx 作为代理,会“隐藏”客户端的真实 IP、协议、主机名。如果你的 Java 应用(如 Spring Boot)需要记录访问日志、做权限校验、生成完整 URL,就必须依赖 Nginx 传递的头部信息。

@RestController
@RequestMapping("/api/v1")
public class UserController {
    @GetMapping("/users")
    public ResponseEntity<String> getUsers(
            HttpServletRequest request) {
        String clientIp = request.getHeader("X-Real-IP");
        String forwardedHost = request.getHeader("Host");
        String scheme = request.getHeader("X-Forwarded-Proto");
        System.out.println("Client IP: " + clientIp);
        System.out.println("Original Host: " + forwardedHost);
        System.out.println("Protocol: " + scheme);
        return ResponseEntity.ok("Hello from Java backend!");
    }
}

对应的 Nginx 配置必须包含:

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;

为什么需要 X-Forwarded-For
因为客户端真实 IP 可能经过多层代理(CDN、负载均衡器等),$proxy_add_x_forwarded_for 会追加每一层的 IP,形成链式记录,如:192.168.1.10, 10.0.0.5, 172.16.0.1

实际项目中,Spring Boot 可通过 server.forward-headers-strategy=native + spring-boot-starter-web 自动识别这些头,无需手动解析。但理解其原理,对排查问题至关重要。

二、域名转发:一个 Nginx 实例,服务多个业务域

现实世界中,很少有系统只服务一个域名。你可能有:

  • api.yourcompany.com → 提供 REST API
  • admin.yourcompany.com → 管理后台
  • static.yourcompany.com → 静态资源
  • legacy.yourcompany.com → 旧系统迁移中

Nginx 的 server 块可以定义多个,每个 server_name 对应一个独立的虚拟主机。这是实现多租户、多服务统一入口的核心手段。

2.1 多域名基础配置示例

# 1. API 服务
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    location / {
        proxy_pass http://api-backend:8080;
        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;
    }
}
# 2. 管理后台
server {
    listen 443 ssl;
    server_name admin.yourcompany.com;
    ssl_certificate /etc/ssl/certs/admin.crt;
    ssl_certificate_key /etc/ssl/private/admin.key;
    location / {
        proxy_pass http://admin-backend:9090;
        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. 静态资源(可缓存)
server {
    listen 443 ssl;
    server_name static.yourcompany.com;
    ssl_certificate /etc/ssl/certs/static.crt;
    ssl_certificate_key /etc/ssl/private/static.key;
    location / {
        root /var/www/static;
        add_header Cache-Control "public, max-age=31536000";
        add_header Access-Control-Allow-Origin "*";
    }
}

你可以在 https://httpbin.org/headers 测试你的请求头是否正确传递。只需用浏览器访问该链接,它会返回你发送的所有 HTTP 头信息,包括 HostX-Forwarded-* 等。

2.2 通配符域名与子域名泛解析

假设你的系统支持多租户,每个租户都有独立子域名:

  • tenant1.yourcompany.com
  • tenant2.yourcompany.com
  • *.yourcompany.com

Nginx 支持正则表达式和通配符:

server {
    listen 443 ssl;
    server_name ~^(?<tenant>.+)\.yourcompany\.com$;
    ssl_certificate /etc/ssl/certs/wildcard.crt;
    ssl_certificate_key /etc/ssl/private/wildcard.key;
    # 从域名中提取租户 ID,传递给后端
    set $tenant_id $tenant;
    location / {
        proxy_pass http://tenant-service:8080;
        proxy_set_header X-Tenant-ID $tenant_id;  # 自定义头,后端可读取
        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;
    }
}

在 Java 中,你可以这样获取租户 ID:

@GetMapping("/dashboard")
public ResponseEntity<Map<String, Object>> getDashboard(
        HttpServletRequest request) {
    String tenantId = request.getHeader("X-Tenant-ID");
    if (tenantId == null || tenantId.isEmpty()) {
        return ResponseEntity.status(403).body(Map.of("error", "Tenant ID required"));
    }
    // 根据 tenantId 查询数据库,返回租户专属数据
    DashboardData data = dashboardService.findByTenant(tenantId);
    return ResponseEntity.ok(data.toMap());
}

这种模式广泛用于 SaaS 平台,如 Notion、Airtable、Salesforce 的多租户架构。无需为每个租户部署独立服务,一个后端实例即可处理所有子域名请求。

2.3 域名重定向:从 HTTP 到 HTTPS,从旧域到新域

你可能需要将旧域名迁移到新域名,或强制所有流量走 HTTPS:

# 强制 HTTP 跳转到 HTTPS
server {
    listen 80;
    server_name api.yourcompany.com www.api.yourcompany.com;
    return 301 https://$host$request_uri;
}
# 旧域名重定向到新域名
server {
    listen 443 ssl;
    server_name legacy.yourcompany.com;
    ssl_certificate /etc/ssl/certs/legacy.crt;
    ssl_certificate_key /etc/ssl/private/legacy.key;
    location / {
        return 301 https://api.yourcompany.com$request_uri;
    }
}

return 301 是永久重定向,搜索引擎会更新索引,浏览器也会缓存该跳转,提升 SEO 和用户体验。

三、路径重写:让后端“看不见”前端路径

路径重写(Rewrite)是 Nginx 最强大的功能之一。它允许你在请求被转发前,动态修改请求的 URI,而用户和浏览器对此完全无感知。

3.1 使用 rewrite 指令:基础语法

rewrite regex replacement [flag];
  • regex:正则表达式,匹配请求路径
  • replacement:替换后的路径
  • flag:可选标志,如 lastbreakredirectpermanent

示例 1:重写/old-api/xxx→/new-api/xxx

location /old-api/ {
    rewrite ^/old-api/(.*)$ /new-api/$1 last;
    proxy_pass http://backend:8080;
}

请求:/old-api/v1/users/123
→ 被重写为:/new-api/v1/users/123
→ 转发到:http://backend:8080/new-api/v1/users/123

注意:rewrite 发生在 proxy_pass 之前!所以 proxy_pass 只需指向后端的根路径即可。

示例 2:移除 URL 中的版本号(兼容旧客户端)

location ~ ^/v[0-9]+/api/ {
    rewrite ^/v[0-9]+/(api/.*)$ /$1 last;
    proxy_pass http://backend:8080;
}

请求:/v1/api/users/api/users
请求:/v2/api/orders/api/orders

这个技巧在 API 版本迁移中极为实用。你可以在新版本中逐步淘汰 /v1/,而无需强制所有客户端升级。

3.2 使用 location + proxy_pass 实现更优雅的重写

有时,rewrite 不是最佳选择。更推荐使用 location 的正则匹配 + proxy_pass 带路径的组合。

location ~ ^/v[0-9]+/api/(.*)$ {
    proxy_pass http://backend:8080/api/$1;
    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;
}

这个写法更清晰、更高效,因为:

  • Nginx 在 location 匹配阶段就捕获了路径参数((.*)
  • proxy_pass 直接拼接,无需额外的 rewrite 指令
  • 避免了 rewrite 的额外处理开销

性能对比:在高并发场景下,location + proxy_passrewrite 快 15%-20%,因为减少了正则引擎的二次匹配。

3.3 实战案例:将前端 SPA 路由转发到后端 API

假设你有一个 Vue.js 前端部署在 https://app.yourcompany.com,后端 API 部署在 https://api.yourcompany.com。但你希望用户只记住一个域名:https://app.yourcompany.com

于是你这样配置:

server {
    listen 443 ssl;
    server_name app.yourcompany.com;
    ssl_certificate /etc/ssl/certs/app.crt;
    ssl_certificate_key /etc/ssl/private/app.key;
    # 静态资源:前端打包文件
    location / {
        root /var/www/frontend;
        try_files $uri $uri/ /index.html;
    }
    # API 路径重写:所有 /api/* 转发到后端
    location /api/ {
        proxy_pass http://backend:8080/;
        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;
    }
}

前端代码中,你只需写:

// Vue.js / React 请求
axios.get('/api/users'); // 实际请求的是 https://app.yourcompany.com/api/users
// 但 Nginx 会把它转成 http://backend:8080/api/users

无需跨域配置!无需 CORS!前端和后端“看起来”在同一个域下,完美解决同源策略问题!

3.4 复杂路径重写:多级路径映射

想象一个复杂的微服务架构:

用户请求路径实际后端服务说明
/v1/user/profileuser-service:8080/api/v1/profile用户服务
/v1/order/listorder-service:8080/api/v1/orders订单服务
/v1/payment/notifypayment-service:8080/webhook/v1/notify支付回调

你可以用多个 location 实现精准路由:

server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    # 用户服务
    location ~ ^/v1/user/(.*)$ {
        proxy_pass http://user-service:8080/api/v1/$1;
        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;
    }
    # 订单服务
    location ~ ^/v1/order/(.*)$ {
        proxy_pass http://order-service:8080/api/v1/$1;
        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;
    }
    # 支付服务(特殊路径)
    location ~ ^/v1/payment/notify$ {
        proxy_pass http://payment-service:8080/webhook/v1/notify;
        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;
    }
    # 默认兜底:404
    location / {
        return 404;
    }
}

每个服务都有独立的路径空间,互不干扰,易于维护。后端服务无需关心“全局路径前缀”,只专注自己的业务路径。

四、高级技巧:条件路由、负载均衡与动态代理

Nginx 的强大远不止静态配置。它支持基于请求头、Cookie、IP、变量的条件判断,实现智能路由。

4.1 基于 User-Agent 的路由(移动端 vs PC)

map $http_user_agent $backend {
    default "mobile-backend";
    ~*"(Chrome|Firefox|Safari|Edge)" "web-backend";
}
server {
    listen 443 ssl;
    server_name app.yourcompany.com;
    location / {
        proxy_pass http://$backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  • 如果 User-Agent 包含 Chrome/Firefox → 转发到 web-backend
  • 否则(如手机浏览器)→ 转发到 mobile-backend

你可以为移动端部署轻量版 API,减少 JSON 字段、关闭日志、启用压缩,提升体验。

4.2 基于 Cookie 的灰度发布(A/B 测试)

假设你正在发布新版本的用户服务,想让 10% 的用户访问新版。

map $cookie_gateway_version $upstream {
    default "backend-v1";
    "v2" "backend-v2";
}
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    location /api/v1/user {
        proxy_pass http://$upstream/api/v1/user;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

然后在前端代码中,随机设置 Cookie:

// 在用户登录后随机设置
if (Math.random() < 0.1) {
    document.cookie = "gateway_version=v2; path=/; max-age=3600";
}

这种方式无需修改 Nginx 配置,仅通过前端控制 Cookie,即可实现无感知灰度发布。适用于金融、电商等高敏感场景。

4.3 负载均衡:多实例自动分发

upstream user-service {
    server 10.0.0.10:8080 weight=3;
    server 10.0.0.11:8080 weight=1;
    server 10.0.0.12:8080 backup;  # 备用节点
}
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    location /api/v1/user {
        proxy_pass http://user-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • weight=3:每 4 个请求,3 个发给 10.0.0.10,1 个发给 10.0.0.11
  • backup:只有当主节点全挂时才启用

📈 Nginx 支持多种负载均衡算法:round-robin(默认)、least_conn(最少连接)、ip_hash(会话保持)

upstream user-service {
    ip_hash;  # 同一 IP 的请求总是发给同一台后端
    server 10.0.0.10:8080;
    server 10.0.0.11:8080;
}

ip_hash 适用于需要会话保持的场景(如购物车、登录态),但牺牲了负载均衡的均匀性。

4.4 动态上游:结合 Lua 或外部服务(进阶)

虽然 Nginx 本身不支持动态 DNS 查询,但可通过 ngx_http_lua_module 实现:

location /dynamic-api {
    content_by_lua_block {
        local res = ngx.location.capture("/resolve-backend")
        local backend = res.body
        ngx.req.set_uri("/api/v1/user", false)
        ngx.var.upstream = backend
        ngx.exec("/proxy-to-backend")
    }
}

这需要 OpenResty 环境,适合高阶用户。普通场景建议使用 Consul + nginx-upsync-module 实现动态上游更新。

五、Java 后端实战:如何配合 Nginx 构建现代化网关

现在,我们来构建一个完整的 Java 微服务 + Nginx 反向代理系统。

5.1 后端服务:Spring Boot API

package com.example.gatewaydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
@RestController
public class GatewayDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayDemoApplication.class, args);
    }
    @GetMapping("/api/v1/user")
    public Map<String, Object> getUserInfo(
            HttpServletRequest request,
            @RequestHeader(value = "X-Tenant-ID", required = false) String tenantId) {
        Map<String, Object> response = new HashMap<>();
        response.put("status", "success");
        response.put("message", "Hello from Java backend!");
        response.put("requestedPath", request.getRequestURI());
        response.put("clientIp", request.getHeader("X-Real-IP"));
        response.put("originalHost", request.getHeader("Host"));
        response.put("tenantId", tenantId);
        response.put("protocol", request.getHeader("X-Forwarded-Proto"));
        return response;
    }
    @GetMapping("/api/v1/health")
    public Map<String, String> health() {
        Map<String, String> health = new HashMap<>();
        health.put("status", "UP");
        health.put("version", "1.2.3");
        return health;
    }
}

启动后,访问 http://localhost:8080/api/v1/user,你会看到:

{
  "status": "success",
  "message": "Hello from Java backend!",
  "requestedPath": "/api/v1/user",
  "clientIp": "127.0.0.1",
  "originalHost": "localhost:8080",
  "tenantId": null,
  "protocol": "http"
}

5.2 Nginx 配置:统一入口 + 路径重写 + 多域名

# 定义上游组
upstream java-backend {
    server 127.0.0.1:8080;
}
server {
    listen 443 ssl;
    server_name api.example.com www.api.example.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    # 所有 /api/v1/* 请求转发到后端
    location ~ ^/api/v1/(.*)$ {
        proxy_pass http://java-backend/api/v1/$1;
        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;
        # 添加安全头
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options DENY;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    }
    # 健康检查端点(不经过重写)
    location /health {
        proxy_pass http://java-backend/health;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    # 默认响应
    location / {
        return 404 "Not Found. Use /api/v1/* endpoints.";
    }
}
# 管理后台
server {
    listen 443 ssl;
    server_name admin.example.com;
    ssl_certificate /etc/ssl/certs/admin.crt;
    ssl_certificate_key /etc/ssl/private/admin.key;
    location / {
        proxy_pass http://java-backend;
        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;
    }
}
# 强制 HTTPS
server {
    listen 80;
    server_name api.example.com www.api.example.com admin.example.com;
    return 301 https://$host$request_uri;
}

5.3 测试验证

  1. 启动 Java 服务:java -jar gateway-demo.jar
  2. 访问:https://api.example.com/api/v1/user

你会看到响应:

{
  "status": "success",
  "message": "Hello from Java backend!",
  "requestedPath": "/api/v1/user",
  "clientIp": "192.168.1.100",
  "originalHost": "api.example.com",
  "tenantId": null,
  "protocol": "https"
}

✅ 注意:originalHostapi.example.com,而非 localhost:8080,说明 Nginx 成功传递了原始域名。

  1. 访问:https://admin.example.com/api/v1/user

你会看到:404 —— 因为后端服务没有 /api/v1/user 路径(它只在 api.example.com 下暴露)

这正是我们想要的:不同域名暴露不同 API,实现逻辑隔离!

六、性能优化与安全加固:生产环境必看

6.1 缓存静态内容

location ~* \.(jpg|jpeg|png|gif|ico|css|js|json|woff|woff2)$ {
    root /var/www/static;
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Access-Control-Allow-Origin "*";
}

减少后端压力,提升前端加载速度。

6.2 限制请求速率(防刷)

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
    location /api/v1/user {
        limit_req zone=api_limit burst=20 nodelay;
        proxy_pass http://java-backend;
        ...
    }
}
  • 每秒最多 10 个请求
  • 允许突发 20 个(burst)
  • nodelay:不延迟,直接拒绝超出部分

6.3 防止恶意请求头

if ($http_user_agent ~* "sqlmap|nmap|nikto") {
    return 403;
}
if ($http_referer ~* "(spam|porn|gambling)") {
    return 403;
}

可结合 nginx-module-vtsModSecurity 做更深度的 WAF 防护。

6.4 启用 Gzip 压缩

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

通常可减少 70% 的响应体积,尤其对 JSON API 效果显著。

七、故障排查与日志分析

7.1 查看 Nginx 配置是否正确

nginx -t

输出 syntax is oktest is successful 才能重启。

7.2 实时查看访问日志

tail -f /var/log/nginx/access.log

典型日志格式:

192.168.1.10 - - [15/Apr/2024:10:23:45 +0800] "GET /api/v1/user HTTP/1.1" 200 1234 "-" "Mozilla/5.0"

7.3 自定义日志格式(记录更多上下文)

log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time" '
                    'host="$host" x-forwarded-for="$http_x_forwarded_for"';
access_log /var/log/nginx/access.log detailed;

日志中将包含:

  • 请求耗时(request_time
  • 上游连接时间(upstream_connect_time
  • 上游响应头时间(upstream_header_time
  • 上游响应体时间(upstream_response_time

一旦后端慢,你就能立即判断是网络问题、后端处理慢,还是数据库慢!

八、架构演进:从 Nginx 到服务网格

随着微服务规模扩大,Nginx 的配置会变得复杂难维护。此时,你可以考虑:

方案适用场景优势劣势
Nginx小中型系统,单一入口配置简单、性能极高、资源消耗低无服务发现、无熔断、无追踪
Spring Cloud GatewayJava 技术栈统一深度集成 Spring 生态、支持断路器、重试JVM 开销大、不适合静态资源
Envoy / Istio大型云原生系统服务网格、mTLS、流量镜像、金丝雀发布学习曲线陡峭、运维复杂

建议路径
小团队 → Nginx 精细化配置
中型团队 → Nginx + Prometheus + Grafana 监控
大型团队 → Istio + K8s + Linkerd

九、总结:你掌握的,不只是配置,是架构话语权

通过本文,你已经掌握了:

✅ Nginx 反向代理的核心原理
✅ 域名转发的多租户实现
✅ 路径重写的四种优雅写法
✅ Java 后端如何感知真实请求
✅ 负载均衡、灰度发布、限流、安全头
✅ 生产环境最佳实践与故障排查

更重要的是,你理解了:

Nginx 不是“转发工具”,它是你的“流量指挥官”
它让你能在不改动一行后端代码的前提下,完成:

  • 多域名隔离
  • API 版本平滑迁移
  • 租户路由
  • 灰度发布
  • 安全加固
  • 性能优化

这,就是架构师的底气。

十、延伸思考:如果你是 CTO,你会怎么设计?

想象你负责一个年交易额 10 亿的电商平台,有:

  • 10 个微服务(用户、商品、订单、支付、库存、推荐、风控、物流、通知、后台)
  • 3 个前端(Web、App、小程序)
  • 5 个地域数据中心
  • 每天 5000 万次 API 调用

你会如何设计 Nginx 层?

建议架构:

[全球用户]
     ↓
[CDN 缓存静态资源]
     ↓
[边缘 Nginx(全球 10 节点)]
     ↓
[区域 Nginx(北京/上海/广州)]
     ↓
[服务网关(Spring Cloud Gateway)]
     ↓
[微服务集群(K8s)]
  • CDN:缓存图片、CSS、JS
  • 边缘 Nginx:做 DDOS 防护、IP 黑名单、SSL 终止
  • 区域 Nginx:做地域路由(如华北用户走华北机房)
  • 网关:做鉴权、限流、日志、熔断
  • 微服务:专注业务逻辑

Nginx 在这里,是流量的过滤器、加速器、调度器,不是简单的代理。

结语:让配置成为艺术

配置文件不是冰冷的文本,它是你系统架构的蓝图,是你与流量对话的语言。

当你能用一行 proxy_pass,让千万用户无感知地切换后端服务;
当你能用一个 rewrite,让旧系统优雅退场;
当你能用一个 map,让 A/B 测试毫秒级生效——

你,就不再是“写代码的人”,而是系统架构的设计师

Nginx 的力量,不在于它能做什么,而在于它让你不用做什么
你无需改 Java 代码,无需重启服务,无需发布新版本,就能完成一次全局流量重构。

这就是反向代理的终极魅力。

附录:常用 Nginx 指令速查表

指令用途
proxy_pass转发请求到后端
proxy_set_header设置转发头
rewrite重写 URI
location匹配请求路径
upstream定义后端集群
limit_req限流
gzip启用压缩
expires设置缓存
return返回 HTTP 状态码
map变量映射(强大!)
try_files优先查找本地文件

以上就是Nginx反向代理之域名转发与路径重写配置指南的详细内容,更多关于Nginx域名转发与路径重写配置的资料请关注脚本之家其它相关文章!

相关文章

  • 使用LDAP实现Nginx用户认证的示例

    使用LDAP实现Nginx用户认证的示例

    本文主要使用Nginx和LDAP实现用户认证,通过配置Nginx和安装nginx-auth-ldap模块,可以实现基于LDAP的认证逻辑,下面就来介绍一下,感兴趣的可以了解一下
    2024-12-12
  • 前端项目中Nginx配置指南详解

    前端项目中Nginx配置指南详解

    这篇文章主要为大家详细介绍了在前端项目开发中如何配置Nginx,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-09-09
  • Linux下Nginx安装教程

    Linux下Nginx安装教程

    这篇文章主要为大家详细介绍了Linux中Nginx的安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • Forever+nginx部署Node站点的方法示例

    Forever+nginx部署Node站点的方法示例

    这篇文章主要介绍了Forever+nginx部署Node站点的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • nginx+lua+redis 灰度发布实现方案

    nginx+lua+redis 灰度发布实现方案

    在微服务化进程中,利用nginx+lua+redis实现灰度发布至关重要,,通过nginx+lua反向代理,根据客户端ip进行路由控制,配合redis存储允许访问微服务的ip地址,可以有效地进行用户分流,感兴趣的可以了解一下
    2024-10-10
  • Nginx 上传大文件超时解决办法

    Nginx 上传大文件超时解决办法

    这篇文章主要介绍了Nginx 上传大文件超时解决办法的相关资料,这里上传文件并设置nginx的配置文件防止超时的情况,需要的朋友可以参考下
    2017-07-07
  • 通过配置nginx访问服务器静态资源的过程

    通过配置nginx访问服务器静态资源的过程

    文章介绍了图片存储路径设置、Nginx服务器配置及通过http://192.168.206.170:8007/a.png访问图片的方法,涵盖图片管理与服务部署的核心步骤
    2025-08-08
  • nginx封空user_agent实现封禁迅雷的方法

    nginx封空user_agent实现封禁迅雷的方法

    nginx封空user_agent实现封禁迅雷的方法,需要的朋友可以参考下。
    2010-11-11
  • nginx访问控制的实现示例

    nginx访问控制的实现示例

    这篇文章主要介绍了nginx访问控制的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • nginx处理http请求实例详解

    nginx处理http请求实例详解

    这篇文章主要介绍了nginx处理http请求实例详解的相关资料,需要的朋友可以参考下
    2017-06-06

最新评论