Skip to content

反向代理与网关:Nginx / API Gateway 在系统中的位置

💡 学习指南:反向代理解决的是"流量怎么分发",API 网关解决的是"请求怎么处理"。本章节会围绕一个问题展开:在高并发的互联网架构中,如何把流量安全、高效地送到正确的服务?

在开始之前,建议你先补两块"基础砖":

  • HTTP 基础:可以先阅读 Web 基础 的「HTTP 协议」部分。
  • 服务器部署:如果你还不熟悉 部署相关概念,建议先了解基础。

0. 引言:为什么网站访问慢了、挂了、被攻击了?

🔄 反向代理 vs 正向代理
一句话区分:正向代理是"客户端的代理",反向代理是"服务器的代理"
👤
用户 (浏览器)
访问域名
🛡️
反向代理 (Nginx)
代理服务器
负载均衡
⚙️
后端服务器集群
Web1 | Web2 | Web3
🛡️ 反向代理特点
  • 客户端无感知,只需要访问域名
  • 隐藏真实服务器架构,统一对外接口
  • 提供负载均衡、安全防护、SSL卸载等功能
  • 典型代表:Nginx、HAProxy、AWS ELB
💡 典型使用场景
  • 网站需要承载高并发流量(负载均衡)
  • 统一HTTPS证书管理(SSL卸载)
  • 防护DDoS攻击和SQL注入
  • 灰度发布、A/B测试、蓝绿部署
🧠 记忆口诀

"反向代理 = 代理服务器" —— 客户端不知道真实服务器,只知道域名

很多人在实际搭建网站时都会遇到类似的情况:

  • 网站流量一高就卡顿,用户体验很差;
  • 某台服务器宕机,整个网站就不可用了;
  • 网站被 DDoS 攻击,服务器直接被打垮;
  • 后台管理接口暴露在外网,被黑客扫描攻击。

直觉上,我们会以为是:"服务器配置不够"。 但大多数时候,问题并不在于服务器"性能差",而在于我们没有把流量处理好

面对这些挑战,单纯依靠"升级服务器"已经捉襟见肘。我们需要一套更系统的流量管理方法,在高并发的场景下,把流量安全、高效地分发到正确的服务。这正是反向代理与网关试图解决的问题。


1. 什么是"反向代理"?(定义 + 场景)

先给一个简短的工作定义,再看几个典型场景。

反向代理,是部署在服务器端的"流量中转站",接收客户端请求,转发给内部服务器,并将响应返回给客户端。客户端只知道反向代理的存在,不知道真实服务器的地址。

你可以简单地把它理解成三件事:接收请求、转发请求、返回响应。 常见会用到它的场景包括:

  • 负载均衡:将流量分发到多台服务器,避免单点压力过大。
  • 安全防护:隐藏真实服务器 IP,防止直接攻击。
  • SSL 终结:在网关层处理 HTTPS,后端服务使用 HTTP,降低计算开销。
  • 动静分离:静态资源直接由 Nginx 返回,动态请求转发给应用服务器。

接下来,我们就从一个真实团队的"踩坑经历"出发,看看他们是怎么一点点从"单机部署"进化到"网关架构"的。


2. 从"血泪教训"说起:某电商大促踩过的坑

本章案例来自 某电商平台(日活千万级用户)。 与普通网站不同,电商平台在双十一等大促期间,流量会呈指数级增长,对系统的稳定性、性能、安全性都提出了极高要求。

这带来了核心矛盾:

  • 如果只用一台服务器:流量一高就宕机,用户体验极差。
  • 如果直接暴露多台服务器:客户端需要知道多个 IP,无法实现负载均衡,而且安全性极差。

该平台的技术团队经历过多次架构重构,才明白一个道理:流量不能只靠"挡",而要靠"疏"和"导"。

2.1 四次重构教会我们什么?

该平台的 CTO 在架构分享会上讲过一个"踩坑史":

阶段遇到的问题当时的想法结果
第一次单台服务器扛不住流量"换一台更好的服务器"流量再涨还是扛不住
第二次多台服务器不知如何分发流量"直接暴露多个 IP 给用户"用户访问混乱,无法实现负载均衡
第三次网站被 DDoS 攻击,真实 IP 暴露"在每台服务器上都配置防火墙"管理复杂,防护效果差
第四次HTTPS 配置复杂,证书管理混乱"每台服务器都配置 SSL 证书"证书更新麻烦,配置不一致

核心领悟不是服务器越多越好,而是流量管理越智能越好

2.2 反向代理到底像什么?

直接暴露服务器 = 没有门卫的大楼

  • 任何人都可以直接找到房间(IP)。
  • 来访者(请求)不知道去哪个房间,可能都挤在一个房间。
  • 安全隐患大,坏人可以直接找到房间搞破坏。

反向代理 = 有前台的大楼

  • 来访者(客户端)只知道前台地址(反向代理 IP)。
  • 前台根据情况把来访者引导到不同的房间(服务器)。
  • 房间的真实位置对外保密,安全性高。

该平台的经验大楼要有前台,流量要过网关


3. 第一步:Nginx 架构 - 为什么它能扛住百万并发?

⚡ Nginx 架构揭秘:为什么它能扛住百万并发?
Master-Worker 进程模型 + 事件驱动 = 高性能的秘诀
Nginx 进程架构图
👑
Master 进程
管理所有 Worker,负责配置加载、平滑升级
4 个 Worker
⚙️
Worker 1
处理 0 请求
⚙️
Worker 2
处理 0 请求
⚙️
Worker 3
处理 0 请求
⚙️
Worker 4
处理 0 请求
📡 epoll (Linux) / kqueue (macOS)
事件驱动:一个 Worker 同时处理数万个连接
传统 Apache
一个连接 = 一个进程/线程
❌ C10K 问题
VS
Nginx
事件驱动 + 异步非阻塞
✅ 百万并发
🎮 模拟请求处理
💡 生产环境建议
Worker 数量 = CPU 核心数(通常设置为 auto,让 Nginx 自动检测)
太多了上下文切换开销大,太少了无法利用多核性能。

在深入配置之前,我们需要理解 Nginx 为什么能处理如此高的并发。这不是魔法,而是精心设计的架构。

3.1 Master-Worker 进程模型

Nginx 采用多进程架构,而不是多线程:

Master 进程(管理者)

  • 负责读取和验证配置文件。
  • 管理 Worker 进程(启动、停止、重新加载)。
  • 不处理具体请求。

Worker 进程(工作者)

  • 实际处理 HTTP 请求。
  • 每个 Worker 是独立的进程,相互隔离。
  • 数量通常设置为 CPU 核心数,避免上下文切换开销。

优势

  • 一个 Worker 崩溃,不会影响其他 Worker。
  • 充分利用多核 CPU。
  • 避免多线程编程的复杂性。

3.2 事件驱动 + 异步非阻塞

这是 Nginx 高性能的核心秘密:

传统 Apache(多进程/线程模型)

  • 一个连接 = 一个进程/线程。
  • 并发数受限于系统进程/线程数。
  • 大量连接时,进程切换开销巨大。

Nginx(事件驱动模型)

  • 使用 epoll(Linux)/ kqueue(macOS)等高效 I/O 多路复用机制。
  • 一个 Worker 进程可以同时处理数万个连接。
  • 连接没有数据时,不会占用 CPU,有新数据时通过事件通知唤醒。

比喻

  • Apache 像餐厅里每个顾客配一个服务员(进程)。
  • Nginx 像一个超级服务员,同时服务所有顾客,谁需要服务就去谁那里,而不是一直站在某个顾客旁边。

3.3 生产环境配置建议

nginx
# 设置 Worker 进程数,通常等于 CPU 核心数
worker_processes auto;

# 设置每个 Worker 的最大连接数
# 总并发连接数 = worker_processes * worker_connections
events {
    worker_connections 4096;
    use epoll;  # Linux 下使用 epoll
    multi_accept on;  # 尽可能接受更多连接
}

http {
    # 开启文件高效传输
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # 长连接超时时间
    keepalive_timeout 65;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript;
}

4. 第二步:API 网关 - 系统的"统一大门"

🚪 API 网关:系统的"统一大门"
想象成写字楼的「前台」——所有访客都要先经过这里,才能到达不同的办公室
客户端 (来访者)
📱 App
💻 Web
🔧 第三方
⬇️ 统一入口
🚪 API 网关 (前台)
🔐身份认证
限流熔断
🧭路由转发
🔄协议转换
⬇️ 分发请求
⚙️ 后端服务 (各个部门)
👤
用户服务
/api/users
📦
订单服务
/api/orders
💳
支付服务
/api/pay
🔐身份认证
统一校验用户身份,无需每个后端服务都写登录逻辑。支持 JWT、OAuth2、API Key 等多种认证方式。
💡 实际场景
用户请求携带 JWT Token,网关校验签名和过期时间,通过后把用户ID添加到请求头转发给后端服务。
🤔 没有网关 vs 有网关的区别
功能需求没有网关 (直接访问)有 API 网关
身份认证每个服务都要写一遍登录校验✅ 统一在网关层校验 JWT
限流保护每个服务自己实现限流✅ 网关统一限流,保护后端
协议转换HTTP、gRPC、WebSocket各自处理✅ 网关统一对外暴露 HTTP
灰度发布需要改负载均衡器配置✅ 网关层按 Header 路由

如果说反向代理是"流量中转站",那么 API 网关就是"智能调度中心"。它不仅仅是转发请求,还承担了很多横切关注点的处理。

4.1 为什么需要 API 网关?

想象一个没有网关的系统:

  • 客户端需要知道多个服务的地址(用户服务、订单服务、支付服务...)。
  • 每个服务都要自己做认证、限流、日志。
  • 协议不统一,有的用 HTTP,有的用 gRPC。
  • 服务升级时,客户端也需要跟着改。

有了 API 网关之后

  • 客户端只需要知道网关地址,网关负责路由到正确服务。
  • 认证、限流、日志等横切逻辑统一在网关处理。
  • 网关可以做协议转换,对外统一暴露 HTTP。
  • 后端服务升级,只需要改网关配置,客户端无感知。

4.2 API 网关的核心功能

功能说明典型场景
路由转发根据 URL、Header 等规则,将请求转发到不同服务/api/users → 用户服务,/api/orders → 订单服务
负载均衡同一个服务有多实例时,分摊流量用户服务有 3 台实例,轮询分发请求
认证鉴权统一校验 JWT、OAuth Token未登录用户无法访问 /api/admin
限流熔断控制流量上限,防止服务被压垮每秒最多 1000 请求,超过返回 429
协议转换对外 HTTP,内部可转 gRPC客户端用 HTTP,网关转 gRPC 调用内部服务
灰度发布按 Header 或比例,将部分流量导到新版本5% 用户体验新版本,95% 用旧版本
日志监控统一记录请求日志,便于分析和排障记录每次请求的耗时、状态码、返回大小

4.3 Nginx vs Kong vs Spring Cloud Gateway

市面上有很多网关产品,如何选择?

维度NginxKongSpring Cloud Gateway
定位高性能反向代理/负载均衡开源 API 网关Spring 生态网关
性能极高(C 语言,事件驱动)高(基于 OpenResty)中等(Java,响应式)
功能基础负载均衡、静态文件、缓存丰富的插件生态(认证、限流、日志等)与 Spring Cloud 深度集成
配置配置文件(nginx.conf)REST API + 配置文件Java 配置 / YAML
扩展C 模块 / Lua 脚本Lua 插件Java 过滤器
适用场景静态资源、七层负载均衡、SSL 终结微服务 API 网关、多租户 SaaSSpring Cloud 微服务架构

选型建议

  • 中小型项目 / 静态资源为主:Nginx 足够。
  • 大型微服务 / 需要丰富插件:Kong。
  • Spring Cloud 全家桶:Spring Cloud Gateway。

5. 第三步:路由与负载均衡 - 把请求送到正确的地方

🧭 路由规则:如何把请求送到正确的服务?
想象成快递分拣中心——根据地址把包裹分配到不同的配送站
🎮 路由规则实验室
输入一个 URL,看看它会被路由到哪个服务
📋 当前路由规则表
优先级匹配规则目标服务路径重写
1Header: X-Version=v2用户服务V2
2Path: /api/users/*用户服务/users/*
3Path: /api/orders/*订单服务/orders/*
4Path: /api/pay/*支付服务/payments/*
5Method: GET, Path: /health健康检查
🚀 快速测试示例
⚖️ 负载均衡:把"压力"均匀分摊到多台服务器
想象成银行的取号系统——把客户均匀分配到各个窗口,避免某个窗口排长队
选择负载均衡策略
🎮 负载均衡模拟器
💡
轮询 - 挨个分发,雨露均沾
按照服务器列表的顺序,依次将请求分配给每台服务器。就像银行叫号,1号窗口完事了到2号,2号完事了到3号,轮着来。
🏢 后端服务器集群
4 台
🖥️
Server-A
21%
请求数:0
权重:4
最近请求:
🖥️
Server-B
40%
请求数:0
权重:1
最近请求:
🖥️
Server-C
34%
请求数:0
权重:4
最近请求:
🖥️
Server-D
28%
请求数:0
权重:2
最近请求:
📨 请求队列
总请求: 0待处理: 0
📊 负载分布统计
31%
平均负载
40%
最高负载
7.1
负载标准差
Server-B
最忙服务器

网关的核心职责之一,就是把请求送到正确的地方。这涉及两个关键能力:路由(去哪台服务器)和负载均衡(怎么分配流量)。

5.1 路由规则:从 URL 到服务

想象一个电商系统,不同的 URL 对应不同的服务:

  • /api/users/* → 用户服务
  • /api/orders/* → 订单服务
  • /api/products/* → 商品服务
  • /api/pay/* → 支付服务

Nginx 配置示例

nginx
server {
    listen 80;
    server_name api.example.com;

    # 用户服务
    location /api/users/ {
        proxy_pass http://user-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 订单服务
    location /api/orders/ {
        proxy_pass http://order-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 商品服务
    location /api/products/ {
        proxy_pass http://product-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 支付服务(需要更高安全级别)
    location /api/pay/ {
        # 限制 IP 访问
        allow 10.0.0.0/8;
        deny all;

        proxy_pass http://payment-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

高级路由规则

nginx
# 基于请求方法的路由
if ($request_method = POST) {
    proxy_pass http://write-service;
}

# 基于 Header 的路由(灰度发布)
if ($http_x_version = "v2") {
    proxy_pass http://api-v2;
}

# 基于 Cookie 的路由(AB 测试)
if ($cookie_test_group = "B") {
    proxy_pass http://variant-b;
}

# 基于 Query 参数的路由
if ($arg_format = "json") {
    proxy_pass http://json-api;
}

5.2 负载均衡:四种策略对比

当同一个服务有多个实例时,如何选择?

策略原理适用场景优点缺点
轮询 (Round Robin)按顺序依次分配给每台服务器服务器性能相近简单公平不考虑服务器当前负载
加权轮询 (Weighted RR)按权重比例分配,权重高的分配更多服务器性能不均充分利用高性能服务器需要合理设置权重
最少连接 (Least Connections)分配给当前连接数最少的服务器长连接场景(WebSocket、视频流)动态适应负载变化需要实时统计连接数
IP 哈希 (IP Hash)根据客户端 IP 计算哈希,同一 IP 永远分配到同一台服务器需要会话保持的场景保证会话一致性某个 IP 流量大时会造成单点压力

Nginx 配置示例

nginx
# 定义 upstream 组
upstream backend {
    # 轮询(默认)
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

upstream backend_weighted {
    # 加权轮询
    server 10.0.1.10:8080 weight=3;  # 性能好,承担更多流量
    server 10.0.1.11:8080 weight=2;
    server 10.0.1.12:8080 weight=1;  # 性能差,承担较少流量
}

upstream backend_least_conn {
    # 最少连接
    least_conn;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

upstream backend_ip_hash {
    # IP 哈希(会话保持)
    ip_hash;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://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;

        # 健康检查(需要第三方模块或 Nginx Plus)
        # health_check;
    }
}

5.3 避坑指南:负载均衡的常见误区

误区 1:忽视健康检查

nginx
# ❌ 错误:没有健康检查,后端服务宕机了,流量还会继续发送
upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;  # 这台宕机了,请求会失败
}

# ✅ 正确:配置健康检查(Nginx Plus 或第三方模块)
upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;

    # 主动健康检查(Nginx Plus 或配置 check 模块)
    check interval=3000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "GET /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

误区 2:会话保持滥用

nginx
# ❌ 错误:所有请求都使用 IP 哈希,导致负载不均
upstream backend {
    ip_hash;  # 某些 IP 流量特别大,导致单点压力
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

# ✅ 正确:需要会话保持的才用 IP 哈希,其他用轮询
upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

upstream backend_session {
    ip_hash;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

server {
    location /api/ {
        proxy_pass http://backend;  # 普通 API,无需会话保持
    }

    location /cart/ {
        proxy_pass http://backend_session;  # 购物车,需要会话保持
    }
}

误区 3:忽视后端获取真实 IP

nginx
# ❌ 错误:后端应用获取到的 IP 是 Nginx 的 IP,不是客户端真实 IP
server {
    location / {
        proxy_pass http://backend;
        # 缺少 Header 设置
    }
}

# ✅ 正确:传递真实 IP 和协议信息
server {
    location / {
        proxy_pass http://backend;

        # 必须设置的 Header
        proxy_set_header Host $host;  # 原始 Host
        proxy_set_header X-Real-IP $remote_addr;  # 客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 代理链
        proxy_set_header X-Forwarded-Proto $scheme;  # 原始协议(http/https)

        # 如果后端也是 Nginx,可以设置真实端口
        proxy_set_header X-Forwarded-Port $server_port;
    }
}

后端应用(以 Node.js Express 为例)获取真实 IP:

javascript
const express = require('express');
const app = express();

// 信任代理(必须设置,否则 X-Forwarded-* 会被忽略)
app.set('trust proxy', true);

app.get('/api/test', (req, res) => {
    res.json({
        // 客户端真实 IP(经过代理链后的第一个 IP)
        realIp: req.ip,

        // 完整的代理链(客户端, 代理1, 代理2, ...)
        forwardedFor: req.get('X-Forwarded-For'),

        // 原始协议(http 或 https)
        protocol: req.protocol,

        // 原始 Host
        host: req.get('Host')
    });
});

app.listen(3000);

4. 第三步:限流与熔断 - 防止系统被"流量洪水"冲垮

⚡ 限流算法:系统不会被"流量洪水"冲垮的秘诀
想象成水坝的闸门——控制水流速度,防止下游被淹没
选择限流算法
🪙 令牌桶算法可视化
令牌桶
🪙
🪙
🪙
🪙
🪙
5 / 10 令牌
⏰ 令牌产生器 (2/秒)
🪙
🪙
🪙
📥 请求队列
📊 三种算法对比
维度令牌桶 (Token Bucket)漏桶 (Leaky Bucket)滑动窗口 (Sliding Window)
核心思想桶里装令牌,有令牌才能通过请求进桶,匀速流出处理统计时间窗口内的请求数
突发流量✅ 允许一定程度的突发(桶里有令牌)❌ 强制平滑,突发会被缓存或拒绝❌ 严格按窗口计数,超出一律拒绝
适用场景API 限流、带宽控制(允许突发)需要严格匀速处理的场景(如消息队列)精确统计(如"1分钟内最多100次")
实现复杂度中等中等较高(需要记录每个时间窗口的请求)
Nginx 配置limit_req_zone (漏桶)limit_req_zone (漏桶)需第三方模块或 Lua
📝 Nginx 限流配置示例
# 定义限流区域
# $binary_remote_addr: 按 IP 限流
# zone=mylimit:10m: 区域名称和大小
# rate=10r/s: 每秒最多10个请求
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

server {
    listen 80;
    server_name api.example.com;

    location / {
        # 应用限流
        # burst=20: 桶容量,允许突发20个请求
        # nodelay: 不延迟处理突发请求
        limit_req zone=mylimit burst=20 nodelay;

        proxy_pass http://backend;
    }
}
💡 配置说明
  • limit_req_zone: 在 http 块中定义限流区域
  • $binary_remote_addr: 使用二进制 IP 地址作为限流键(省内存)
  • zone=mylimit:10m: 区域名称 mylimit,分配 10MB 内存
  • rate=10r/s: 每秒允许 10 个请求(漏桶算法)
  • burst=20: 桶的容量为 20,允许一定程度的突发流量
  • nodelay: 不延迟处理突发请求(立即处理或拒绝)

在高并发场景下,保护系统不被突发流量压垮,是网关的核心职责之一。这需要用到限流熔断机制。

4.1 限流算法对比:令牌桶 vs 漏桶 vs 滑动窗口

算法核心思想突发流量适用场景实现复杂度
令牌桶桶里装令牌,有令牌才能通过允许一定程度的突发API 限流、带宽控制中等
漏桶请求进桶,匀速流出处理强制平滑,突发会被缓存或拒绝需要严格匀速处理的场景中等
滑动窗口统计时间窗口内的请求数严格按窗口计数,超出一律拒绝精确统计(如"1分钟内最多100次")较高

4.2 Nginx 限流配置实战

nginx
# 定义限流区域(放在 http 块中)

# 1. 基于 IP 的限流(漏桶算法)
# zone=mylimit:10m - 区域名称和内存大小(10MB 约可存储 16 万 IP)
# rate=10r/s - 每秒允许 10 个请求
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

# 2. 基于 IP 的连接数限制(防止单个 IP 建立过多连接)
limit_conn_zone $binary_remote_addr zone=addr:10m;

# 3. 基于服务端点的限流(不区分 IP,保护后端整体)
limit_req_zone $server_name zone=server_limit:10m rate=100r/s;

server {
    listen 80;
    server_name api.example.com;

    # 用户服务 - 普通限流
    location /api/users/ {
        # 应用限流
        # burst=20 - 桶容量,允许突发 20 个请求
        # nodelay - 不延迟处理突发请求(立即处理或拒绝)
        limit_req zone=mylimit burst=20 nodelay;

        # 限制单个 IP 的连接数
        limit_conn addr 10;

        proxy_pass http://user-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 订单服务 - 更严格的限流
    location /api/orders/ {
        # 更严格的限流:每秒 5 个请求
        limit_req_zone $binary_remote_addr zone=order_limit:10m rate=5r/s;
        limit_req zone=order_limit burst=10 nodelay;

        proxy_pass http://order-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 支付服务 - 最高级别保护
    location /api/pay/ {
        # 多层限流保护

        # 第一层:单 IP 限流(每秒 2 个请求)
        limit_req_zone $binary_remote_addr zone=pay_ip_limit:10m rate=2r/s;
        limit_req zone=pay_ip_limit burst=5 nodelay;

        # 第二层:全局限流(保护后端数据库)
        limit_req zone=server_limit burst=50 nodelay;

        # 第三层:连接数限制
        limit_conn addr 5;

        # 只允许内网访问(额外安全层)
        allow 10.0.0.0/8;
        deny all;

        proxy_pass http://payment-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # 支付接口增加超时时间
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 限流后的处理
    # 当请求被限流时,返回 429 Too Many Requests
    error_page 429 /429.html;
    location = /429.html {
        internal;
        return 429 '{"error": "Too Many Requests", "message": "Rate limit exceeded. Please try again later."}';
        add_header Content-Type application/json;
    }
}

4.3 熔断降级:当依赖服务出问题时

限流是防止外部流量压垮系统,熔断是防止内部依赖故障扩散。

熔断器的工作原理

  1. 关闭状态:正常转发请求,同时统计错误率。
  2. 开启状态:当错误率超过阈值,熔断器开启,直接返回错误,不再转发请求。
  3. 半开状态:经过一段时间后,允许少量请求通过试探,如果成功则关闭熔断器。

Nginx 实现熔断(使用 Lua 模块或第三方模块)

nginx
# 使用 nginx-upsync-module 或 lua-resty-healthcheck 实现健康检查和熔断

upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;

    # 健康检查(需要 nginx_upstream_check_module)
    check interval=3000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "GET /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

server {
    location / {
        proxy_pass http://backend;

        # 代理错误时返回自定义错误页(降级)
        proxy_intercept_errors on;
        error_page 500 502 503 504 /fallback.html;
    }

    location = /fallback.html {
        internal;
        # 返回降级数据(如缓存数据、简化版页面)
        return 200 '{"status": "degraded", "message": "Service temporarily unavailable. Showing cached data."}';
        add_header Content-Type application/json;
    }
}

使用 OpenResty + Lua 实现更完善的熔断

lua
-- 使用 lua-resty-circuit-breaker 库实现熔断
local circuit_breaker = require "resty.circuit-breaker"

local cb = circuit_breaker.new({
    name = "payment_service",
    group = "payment",
    -- 熔断策略
    failure_threshold = 5,      -- 连续失败 5 次触发熔断
    success_threshold = 2,    -- 连续成功 2 次关闭熔断
    timeout = 60,              -- 熔断后等待 60 秒进入半开状态
    -- 错误类型
    expected_statuses = {200, 201},  -- 期望的 HTTP 状态码
    ignored_statuses = {404, 422},   -- 不计入失败的 status
})

-- 使用熔断器执行请求
local ok, err = cb:execute(function()
    -- 发起 HTTP 请求
    local httpc = require "resty.http".new()
    local res, err = httpc:request_uri("http://payment-service/charge", {
        method = "POST",
        body = body,
        headers = {
            ["Content-Type"] = "application/json",
        },
    })

    if not res then
        return nil, err
    end

    return res
end)

if not ok then
    -- 熔断器开启或请求失败,执行降级逻辑
    ngx.log(ngx.WARN, "Circuit breaker open or request failed: ", err)

    -- 返回降级响应
    ngx.status = 503
    ngx.say('{"error": "Service temporarily unavailable", "fallback": true}')
    return
end

-- 请求成功,返回正常响应
ngx.status = res.status
ngx.say(res.body)

6. 第四步:认证与安全 - 守护大门的"门卫"

🔐 认证中间件:谁可以进大门?
想象成写字楼门禁——检查工牌、验证身份,没权限的人进不来
JWT (JSON Web Token) 认证流程
1
用户
输入用户名密码,点击登录
2
网关/Nginx
转发登录请求到认证服务
3
认证服务
验证密码,生成 JWT Token(包含 Header、Payload、Signature)
4
用户/客户端
保存 Token(LocalStorage 或 Cookie)
5
后续请求
在 HTTP Header 中携带: Authorization: Bearer <Token>
6
网关/Nginx
校验 Token 签名和过期时间,通过后转发请求
7
后端服务
从 Token 中解析用户信息,处理业务逻辑
🔑 JWT Token 结构(Base64编码)
HEADER
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{ "alg": "HS256", "typ": "JWT" }
.
PAYLOAD
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
.
SIGNATURE
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)
🛠️ 三种方案实现对比
对比维度Session + CookieJWTOAuth2.0
存储位置服务端存储 Session,客户端存 Cookie客户端存储 Token,服务端无状态授权服务器存储,客户端存 Access Token
扩展性❌ 需要共享 Session,扩展复杂✅ 无状态,易于水平扩展✅ 分布式架构,支持大规模系统
安全性⚠️ Cookie 可能被窃取,需要 CSRF 防护⚠️ Token 泄露风险,需 HTTPS + 短期有效✅ 行业最佳实践,支持多种安全机制
实现复杂度🟢 简单,开箱即用🟡 中等,需要 Token 管理🔴 复杂,需要授权服务器
适用场景传统 Web 应用、后台管理系统SPA、移动端 API、微服务第三方登录、开放平台、SSO
🔒 网关层认证最佳实践
1
统一在网关层验证
不要在每个微服务里重复写认证逻辑,统一在网关层校验 JWT 或 Session
2
HTTPS 强制
网关层强制 HTTPS,防止 Token 在传输过程中被窃取(中间人攻击)
3
Token 过期策略
Access Token 短期有效(15分钟),配合 Refresh Token 实现无感知续期
4
黑名单机制
用户登出或 Token 泄露时,将 Token 加入黑名单(Redis 存储)

网关是系统的统一入口,自然也成为安全防护的第一道防线。在网关层处理认证和安全,可以避免每个后端服务重复实现。

6.1 在网关层统一认证

传统方式(每个服务各自认证)

  • 用户服务、订单服务、支付服务...每个都要校验 JWT。
  • 代码重复,维护困难。
  • secret 分散在各个服务,泄露风险高。

网关统一认证

  • 客户端携带 Token 访问网关。
  • 网关校验 Token 合法性(签名、过期时间)。
  • 校验通过后,将用户信息(如 user_id)添加到请求头,转发给后端服务。
  • 后端服务无需校验,直接从 Header 获取用户信息。

Nginx + Lua 实现 JWT 校验

nginx
server {
    listen 80;
    server_name api.example.com;

    location / {
        # 使用 access_by_lua_block 进行认证
        access_by_lua_block {
            local jwt = require "resty.jwt"

            -- 从请求头获取 Token
            local auth_header = ngx.var.http_authorization
            if not auth_header then
                ngx.status = 401
                ngx.say('{"error": "Missing authorization header"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end

            -- 提取 Token(Bearer token)
            local token = auth_header:match("^Bearer%s+(.+)$")
            if not token then
                ngx.status = 401
                ngx.say('{"error": "Invalid authorization format"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end

            -- 验证 JWT
            local jwt_obj = jwt:verify("your-secret-key", token)
            if not jwt_obj.verified then
                ngx.status = 401
                ngx.say('{"error": "Invalid or expired token"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end

            -- 将用户信息设置到变量,供后续使用
            ngx.var.user_id = jwt_obj.payload.sub
            ngx.var.user_role = jwt_obj.payload.role
        }

        # 将用户信息传递给后端服务
        proxy_set_header X-User-ID $user_id;
        proxy_set_header X-User-Role $user_role;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_pass http://backend;
    }

    # 公开接口,无需认证
    location /api/public/ {
        proxy_pass http://backend;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

6.2 HTTPS 与 SSL 终结

🔒 SSL 终结:HTTPS 流量的"解密官"
想象成公司的前台接待——对外使用正式头衔(HTTPS),对内用内部称呼(HTTP),负责"翻译"身份
🔐 HTTPS 流量解密流程
👤
客户端 (浏览器)
发起 HTTPS 请求
🔒TLS 加密连接
证书: *.example.com
算法: TLS 1.3
加密: AES-256-GCM
🚪
Nginx (SSL 终结)
📜 校验证书
🔓 解密流量
📝 添加 X-Forwarded-*
🔓HTTP 明文
X-Forwarded-For: 203.0.113.42
X-Forwarded-Proto: https
X-Real-IP: 203.0.113.42
⚙️
后端服务集群
专注于业务逻辑,无需处理 TLS
📜 SSL 证书管理
1
生成私钥
使用 OpenSSL 生成 RSA 私钥,这是证书的基础
openssl genrsa -out private.key 2048
2
创建 CSR
生成证书签名请求,包含域名和组织信息
openssl req -new -key private.key -out csr.pem
3
域名验证
CA 机构验证域名所有权(DNS 记录或 HTTP 文件)
# 添加 DNS TXT 记录 或 上传验证文件到 /.well-known/
4
签发证书
验证通过后,CA 签发证书文件
# 下载 certificate.crt 和 chain.crt
5
部署配置
将证书配置到 Nginx 并测试
nginx -t && systemctl reload nginx
✨ SSL 终结的核心优势
🚀
性能提升
TLS 握手和加密解密是 CPU 密集型操作,集中在 Nginx 处理,后端服务专注业务逻辑,整体吞吐量提升 2-5 倍
🔧
简化运维
证书统一管理,只需在 Nginx 配置一次,无需在每个后端服务重复配置,证书续期、更换一键完成
🛡️
集中安全
SSL/TLS 配置统一管控,强制使用最新协议版本和密码套件,统一添加安全响应头(HSTS、CSP 等)
📊
统一监控
所有 HTTPS 流量经过 Nginx,可以统一记录访问日志、分析 SSL 握手性能、监控证书有效期,便于审计和排障

HTTPS 是现代 Web 应用的标配。但如果在每台后端服务器都配置 HTTPS,会带来很多麻烦:

  • 证书管理复杂,每台服务器都要部署、更新证书。
  • 后端服务需要处理 TLS 握手,消耗 CPU 资源。
  • 配置容易出错,不一致。

SSL 终结(SSL Termination) 方案:

  • 只在网关(Nginx)层配置 HTTPS 和证书。
  • 网关负责 TLS 握手和加解密。
  • 网关和后端服务之间使用 HTTP 明文传输(内部网络可信)。
  • 后端服务专注于业务逻辑,无需处理 TLS。

SSL 终结流程

  1. 客户端发送 HTTPS 请求到 Nginx。
  2. Nginx 和客户端完成 TLS 握手,建立加密通道。
  3. Nginx 解密请求,得到明文 HTTP 请求。
  4. Nginx 将明文 HTTP 请求转发给后端服务(通过内部网络)。
  5. 后端服务处理请求,返回明文 HTTP 响应给 Nginx。
  6. Nginx 加密响应,通过 HTTPS 返回给客户端。

Nginx HTTPS 配置

nginx
server {
    # 监听 443 端口,启用 SSL
    listen 443 ssl http2;
    server_name api.example.com;

    # SSL 证书配置
    ssl_certificate /etc/nginx/ssl/api.example.com.crt;  # 证书文件
    ssl_certificate_key /etc/nginx/ssl/api.example.com.key;  # 私钥文件

    # SSL 协议和密码套件(安全配置)
    ssl_protocols TLSv1.2 TLSv1.3;  # 只启用安全的 TLS 版本
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;  # 强密码套件
    ssl_prefer_server_ciphers off;  # 优先使用客户端支持的密码套件

    # SSL 会话缓存(提升性能)
    ssl_session_cache shared:SSL:50m;  # 会话缓存大小
    ssl_session_timeout 1d;  # 会话超时时间
    ssl_session_tickets off;  # 禁用会话票证(前向安全)

    # OCSP Stapling(提升性能和隐私)
    ssl_stapling on;  # 启用 OCSP Stapling
    ssl_stapling_verify on;  # 验证 OCSP 响应
    ssl_trusted_certificate /etc/nginx/ssl/chain.crt;  # 信任链
    resolver 8.8.8.8 8.8.4.4 valid=300s;  # DNS 解析器
    resolver_timeout 5s;  # DNS 解析超时

    # 安全响应头
    add_header Strict-Transport-Security "max-age=63072000" always;  # HSTS
    add_header X-Frame-Options "SAMEORIGIN" always;  # 防止点击劫持
    add_header X-Content-Type-Options "nosniff" always;  # 防止 MIME 嗅探
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;  # Referrer 策略

    # SSL 终结后,转发到后端 HTTP 服务
    location / {
        proxy_pass http://backend;  # 后端使用 HTTP
        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)
        proxy_set_header X-Forwarded-Port 443;  # 传递原始端口
    }
}

# HTTP 重定向到 HTTPS(强制 HTTPS)
server {
    listen 80;
    server_name api.example.com;

    # 所有 HTTP 请求 301 重定向到 HTTPS
    return 301 https://$server_name$request_uri;
}

6.3 安全配置清单

配置项说明推荐值
SSL 协议启用的 TLS 版本TLSv1.2 TLSv1.3(禁用 SSLv3、TLSv1.0/1.1)
密码套件加密算法组合优先使用 ECDHE + AES-GCM,禁用 RC4DESMD5
HSTS强制 HTTPSmax-age=63072000(两年)
证书有效期SSL 证书过期时间不超过 397 天(行业规范)
OCSP Stapling证书状态检查启用,提升性能和隐私
Session Tickets会话恢复机制禁用(前向安全考虑)或定期轮换密钥

7. 系统整合:打造完整的网关架构

现在,是时候把之前学到的所有组件整合起来,搭建一个完整的网关架构了。

7.1 完整架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           客户端(浏览器/APP)                                 │
└───────────────────────────────┬─────────────────────────────────────────────┘
                                │ HTTPS

┌─────────────────────────────────────────────────────────────────────────────┐
│                           外层:CDN + WAF                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  CDN(内容分发网络)                                                 │   │
│  │  - 静态资源缓存(图片、CSS、JS)                                      │   │
│  │  - 就近访问,降低延迟                                                 │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  WAF(Web 应用防火墙)                                                │   │
│  │  - 防护 SQL 注入、XSS 攻击                                            │   │
│  │  - 拦截恶意 Bot、爬虫                                                 │   │
│  │  - CC 攻击防护(Challenge Collapsar)                                 │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│                        中层:API 网关(Nginx/Kong)                           │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  第一层:SSL 终结 + 安全防护                                          │   │
│  │  - HTTPS / TLS 1.3                                                   │   │
│  │  - HSTS、安全响应头                                                   │   │
│  │  - OCSP Stapling                                                    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  第二层:认证与鉴权                                                    │   │
│  │  - JWT Token 校验                                                    │   │
│  │  - OAuth 2.0 / SSO 集成                                               │   │
│  │  - API Key 管理                                                       │   │
│  │  - 权限校验(RBAC)                                                   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  第三层:流量控制                                                      │   │
│  │  - 限流(Rate Limiting)- 令牌桶/漏桶算法                              │   │
│  │  - 熔断(Circuit Breaking)- 防止故障扩散                               │   │
│  │  - 降级(Degradation)- 服务不可用时的备用方案                           │   │
│  │  - 灰度发布(Canary Release)- 按比例分配流量                            │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  第四层:路由与负载均衡                                                 │   │
│  │  - 路径路由(Path-based Routing)                                      │   │
│  │  - 域名路由(Host-based Routing)                                      │   │
│  │  - Header 路由(Header-based Routing)                                 │   │
│  │  - 负载均衡算法(轮询/加权/最少连接/IP 哈希)                             │   │
│  │  - 服务发现(Service Discovery)集成                                    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  第五层:协议转换与数据处理                                             │   │
│  │  - SSL 终结(HTTPS ↔ HTTP)                                           │   │
│  │  - 协议转换(HTTP ↔ gRPC / WebSocket)                                 │   │
│  │  - 请求/响应转换(JSON ↔ XML)                                         │   │
│  │  - 数据压缩(Gzip / Brotli)                                           │   │
│  │  - 缓存(Cache)- 静态资源和 API 响应                                    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│                         内层:微服务集群                                     │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │  用户服务    │  │  订单服务    │  │  商品服务    │  │  支付服务    │          │
│  │  User Svc   │  │  Order Svc  │  │ Product Svc │  │ Payment Svc │          │
│  │             │  │             │  │             │  │             │          │
│  │  服务注册    │  │  服务注册    │  │  服务注册    │  │  服务注册    │          │
│  │   Consul    │  │   Consul    │  │   Consul    │  │   Consul    │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
│         │                │                │                │               │
│         └────────────────┴────────────────┴────────────────┘               │
│                                       │                                      │
│                    服务发现与配置中心(Consul / etcd)                          │
│                    - 服务注册与发现                                            │
│                    - 健康检查                                                  │
│                    - KV 配置存储                                              │
└─────────────────────────────────────────────────────────────────────────────┘

7.2 实战代码模板:完整的 Nginx 网关配置

nginx
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;  # 自动设置为 CPU 核心数
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

# 加载动态模块(根据实际需要启用)
# load_module modules/ngx_http_geoip2_module.so;

# 工作模式和连接数上限
events {
    use epoll;  # Linux 下使用 epoll
    worker_connections 4096;  # 每个 Worker 的最大连接数
    multi_accept on;  # 尽可能接受更多连接
}

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" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';

    access_log /var/log/nginx/access.log main;

    # 性能优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 1000;
    gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

    # 安全响应头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # 防止点击劫持(可选)
    # add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'self';" always;

    # 上游服务定义
    # 用户服务(加权轮询)
    upstream user_service {
        server 10.0.1.10:8080 weight=3;
        server 10.0.1.11:8080 weight=2;
        keepalive 32;
    }

    # 订单服务(最少连接)
    upstream order_service {
        least_conn;
        server 10.0.1.20:8080;
        server 10.0.1.21:8080;
        server 10.0.1.22:8080;
        keepalive 32;
    }

    # 商品服务(IP 哈希,会话保持)
    upstream product_service {
        ip_hash;
        server 10.0.1.30:8080;
        server 10.0.1.31:8080;
        keepalive 32;
    }

    # 支付服务(严格的负载均衡 + 健康检查)
    upstream payment_service {
        server 10.0.1.40:8080 weight=2;
        server 10.0.1.41:8080 backup;  # 备份服务器
        keepalive 32;
    }

    # 限流区域定义
    # 普通 API 限流:每秒 10 请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 严格限流:每秒 2 请求(用于敏感接口)
    limit_req_zone $binary_remote_addr zone=strict_limit:10m rate=2r/s;

    # 全局限流:保护后端整体
    limit_req_zone $server_name zone=global_limit:10m rate=100r/s;

    # 连接数限制
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # 虚拟主机配置
    server {
        listen 80;
        server_name api.example.com;

        # 强制 HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name api.example.com;

        # SSL 配置(略,见上文)
        ssl_certificate /etc/nginx/ssl/api.example.com.crt;
        ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
        # ... 其他 SSL 配置

        # 全局限流
        limit_req zone=global_limit burst=200 nodelay;

        # ===== 用户服务路由 =====
        location /api/users/ {
            # 应用限流
            limit_req zone=api_limit burst=20 nodelay;
            limit_conn conn_limit 10;

            # 超时设置
            proxy_connect_timeout 5s;
            proxy_send_timeout 10s;
            proxy_read_timeout 10s;

            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;
            proxy_set_header X-Forwarded-Proto $scheme;

            # 错误处理
            proxy_intercept_errors on;
            error_page 500 502 503 504 /error.html;
        }

        # ===== 订单服务路由 =====
        location /api/orders/ {
            # 更严格的限流
            limit_req zone=strict_limit burst=10 nodelay;
            limit_conn conn_limit 5;

            proxy_pass http://order_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;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # ===== 商品服务路由 =====
        location /api/products/ {
            # 缓存静态资源
            location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
                expires 30d;
                add_header Cache-Control "public, immutable";
            }

            proxy_pass http://product_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;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # ===== 支付服务路由(最高安全级别) =====
        location /api/pay/ {
            # 多重限流保护
            limit_req zone=strict_limit burst=5 nodelay;
            limit_req zone=global_limit burst=50 nodelay;
            limit_conn conn_limit 3;

            # 只允许内网访问(额外安全层)
            allow 10.0.0.0/8;
            allow 172.16.0.0/12;
            allow 192.168.0.0/16;
            deny all;

            # 详细日志记录
            access_log /var/log/nginx/payment-access.log detailed;

            proxy_pass http://payment_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;
            proxy_set_header X-Forwarded-Proto $scheme;

            # 支付接口增加超时时间
            proxy_connect_timeout 30s;
            proxy_send_timeout 30s;
            proxy_read_timeout 30s;
        }

        # 健康检查端点
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }

        # 错误页面
        location /error.html {
            internal;
            root /var/www/html;
        }

        # 限流错误处理
        error_page 429 /429.html;
        location = /429.html {
            internal;
            return 429 '{"error": "Too Many Requests", "message": "Rate limit exceeded. Please try again later."}';
            add_header Content-Type application/json;
        }
    }
}

7.3 为什么这样设计最强?

这个架构的设计哲学,是为了解决三个核心矛盾:

1. 高性能与高可用(负载均衡 + 健康检查)

  • 矛盾:单台服务器性能有限,容易成为瓶颈;多台服务器需要协调,避免单点故障。
  • 解法:使用 Nginx 作为负载均衡器,支持多种负载均衡算法(轮询、加权、最少连接、IP 哈希)。配合健康检查,自动剔除故障节点,保证服务高可用。

2. 安全性与易用性(SSL 终结 + 统一认证)

  • 矛盾:HTTPS 保证安全,但配置复杂、证书管理麻烦;每个服务都认证,代码重复、维护困难。
  • 解法:在 Nginx 层统一做 SSL 终结和认证。客户端只需信任 Nginx 的证书,后端服务之间使用 HTTP 明文通信,简化配置。认证逻辑统一在网关处理,后端服务专注于业务逻辑。

3. 灵活性与稳定性(限流熔断 + 灰度发布)

  • 矛盾:新功能需要快速上线验证,但全量发布风险大;突发流量可能压垮系统,需要保护机制。
  • 解法:使用 Nginx 的限流和熔断功能,防止系统被突发流量压垮。配合灰度发布,按 Header 或比例将部分流量导到新版本,验证稳定性后再全量上线。

8. 实战模板:直接抄作业

为了让你更直观地理解这套机制是如何运作的,我们为你准备了全链路配置模板

场景 1:中小型 Web 应用(单域名,多服务)

适用场景:创业公司官网 + 后台管理 + API 服务

nginx
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    use epoll;
    worker_connections 4096;
    multi_accept on;
}

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;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 1000;
    gzip_types text/plain text/css text/xml application/json application/javascript;

    # 安全响应头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # 上游服务
    upstream app_servers {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        keepalive 32;
    }

    upstream api_servers {
        server 127.0.0.1:4000;
        keepalive 32;
    }

    # 限流配置
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s;

    # HTTP 服务器
    server {
        listen 80;
        server_name example.com www.example.com;

        # 强制 HTTPS(生产环境启用)
        # return 301 https://$server_name$request_uri;

        # 静态文件
        location /static/ {
            alias /var/www/html/static/;
            expires 30d;
            add_header Cache-Control "public, immutable";
        }

        location /images/ {
            alias /var/www/html/images/;
            expires 90d;
            add_header Cache-Control "public, immutable";
        }

        # 前端应用
        location / {
            limit_req zone=general burst=20 nodelay;

            proxy_pass http://app_servers;
            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;
        }

        # API 接口
        location /api/ {
            limit_req zone=api burst=40 nodelay;

            proxy_pass http://api_servers;
            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 /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }

    # HTTPS 服务器(生产环境启用)
    # server {
    #     listen 443 ssl http2;
    #     server_name example.com www.example.com;
    #
    #     ssl_certificate /etc/nginx/ssl/example.com.crt;
    #     ssl_certificate_key /etc/nginx/ssl/example.com.key;
    #     ssl_protocols TLSv1.2 TLSv1.3;
    #     ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    #     ssl_prefer_server_ciphers off;
    #     ssl_session_cache shared:SSL:50m;
    #     ssl_session_timeout 1d;
    #
    #     # 复制 HTTP 服务器的 location 配置
    #     # ...
    # }
}

场景 2:微服务架构(多域名,复杂路由)

适用场景:大型互联网公司,多业务线,多团队协作

nginx
# 微服务架构下的 Nginx 配置示例
# 特点:多域名、复杂路由、服务发现集成

# 服务发现集成(使用 Consul 或 etcd)
# 需要 nginx-upsync-module 模块
upstream user_service {
    # 从 Consul 自动发现服务实例
    upsync 127.0.0.1:8500/v1/catalog/service/user-service upsync_timeout=6m upsync_interval=500ms;
    upsync_dump_path /var/nginx/conf/user_service.conf;

    # 默认服务器(Consul 不可用时使用)
    server 127.0.0.1:11111 down;

    keepalive 64;
    keepalive_timeout 60s;
    keepalive_requests 1000;
}

# 动态 upstream 示例(Lua + Redis)
upstream dynamic_backend {
    server 0.0.0.0;  # 占位符

    balancer_by_lua_block {
        local balancer = require "ngx.balancer"
        local resty_redis = require "resty.redis"

        -- 从 Redis 获取可用后端列表
        local redis = resty_redis:new()
        redis:connect("127.0.0.1", 6379)

        local backends, err = redis:smembers("backends:available")
        if not backends or #backends == 0 then
            ngx.log(ngx.ERR, "no available backends")
            return ngx.exit(503)
        end

        -- 简单的轮询选择
        local hash = ngx.var.remote_addr .. ngx.var.request_uri
        local index = ngx.crc32_short(hash) % #backends + 1
        local selected = backends[index]

        -- 设置后端地址
        local ok, err = balancer.set_current_peer(selected, 80)
        if not ok then
            ngx.log(ngx.ERR, "failed to set peer: ", err)
            return ngx.exit(500)
        end
    }
}

# 基于 Host 的多域名路由
server {
    listen 80;
    server_name api.user.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.user.example.com;

    ssl_certificate /etc/nginx/ssl/user.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/user.example.com.key;

    # JWT 认证(使用 Lua)
    access_by_lua_block {
        local jwt = require "resty.jwt"

        local auth_header = ngx.var.http_authorization
        if not auth_header then
            ngx.exit(401)
        end

        local token = auth_header:match("^Bearer%s+(.+)$")
        if not token then
            ngx.exit(401)
        end

        local jwt_obj = jwt:verify(os.getenv("JWT_SECRET"), token)
        if not jwt_obj.verified then
            ngx.exit(401)
        end

        -- 将用户信息设置到变量
        ngx.var.user_id = jwt_obj.payload.sub
        ngx.var.user_role = jwt_obj.payload.role
    }

    location / {
        # 权限控制
        if ($user_role != "user" && $user_role != "admin") {
            return 403;
        }

        proxy_pass http://user_service;
        proxy_set_header Host $host;
        proxy_set_header X-User-ID $user_id;
        proxy_set_header X-User-Role $user_role;
        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;
    }
}

# Admin API(管理后台,更严格的权限控制)
server {
    listen 443 ssl http2;
    server_name api.admin.example.com;

    ssl_certificate /etc/nginx/ssl/admin.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/admin.example.com.key;

    # IP 白名单(只允许公司内网访问)
    allow 10.0.0.0/8;
    allow 172.16.0.0/12;
    allow 192.168.0.0/16;
    deny all;

    # 严格的限流
    limit_req zone=strict_limit burst=5 nodelay;
    limit_conn conn_limit 5;

    # 只允许管理员角色访问
    set $admin_required 1;

    location / {
        if ($user_role != "admin") {
            return 403;
        }

        proxy_pass http://admin_service;
        proxy_set_header Host $host;
        proxy_set_header X-User-ID $user_id;
        proxy_set_header X-User-Role $user_role;
        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;
    }
}

9. 名词对照表

英文术语中文对照解释
Reverse Proxy反向代理部署在服务器端,接收客户端请求并转发给内部服务器的代理服务。客户端只知道反向代理的存在,不知道真实服务器地址。
Forward Proxy正向代理部署在客户端侧,代替客户端访问外部资源的代理服务。服务端看到的是代理的 IP,不知道真实客户端。典型应用:VPN、翻墙工具。
API GatewayAPI 网关位于客户端和后端服务之间的中间层,提供路由、认证、限流、日志等功能,是微服务架构的"统一大门"。
Load Balancing负载均衡将请求流量分配到多台服务器,避免单台服务器过载,提高系统可用性和性能。
Rate Limiting限流限制单位时间内的请求数量,防止系统被突发流量压垮。常用算法:令牌桶、漏桶、滑动窗口。
Circuit Breaking熔断当依赖服务出现故障时,自动切断调用,防止故障扩散,并提供降级方案。
SSL TerminationSSL 终结在网关层处理 HTTPS 加密解密,后端服务使用 HTTP,降低后端计算开销,简化证书管理。
Health Check健康检查定期检查后端服务的健康状态,自动剔除故障节点,保证流量只发送到健康的服务实例。
Sticky Session会话保持将同一客户端的请求始终路由到同一台后端服务器,用于需要保持会话状态的场景。
Blue-Green Deployment蓝绿部署同时运行两个生产环境(蓝、绿),切换流量实现零停机发布。
Canary Release灰度发布将少量流量导到新版本,验证稳定性后逐步扩大比例,降低发布风险。
Upstream上游在 Nginx 配置中,指代后端服务器组。
Location位置块Nginx 中用于匹配请求 URL 并定义处理规则的配置块。
Worker Process工作进程Nginx 中实际处理请求的进程,多个 Worker 并行工作,充分利用多核 CPU。
Master Process主进程Nginx 中负责管理 Worker 进程(启动、停止、重新加载配置)的控制进程。
Event-Driven事件驱动一种编程模型,通过监听和响应事件(如 I/O 就绪)来处理并发,Nginx 的核心架构。
epoll / kqueueI/O 多路复用Linux/macOS 下的高性能 I/O 事件通知机制,允许单个进程同时处理大量连接。

总结:反向代理与网关的本质

经过这一章的学习,我们可以得出几个核心结论:

从实践来看

  • 反向代理解决的是"流量怎么分发"的问题,通过负载均衡、健康检查、会话保持等机制,将流量高效、可靠地送达后端服务。
  • API 网关解决的是"请求怎么处理"的问题,在统一的入口点处理横切关注点(认证、限流、日志等),让后端服务专注于业务逻辑。

从架构视角看

  • 网关是系统的"门面",所有流量都经过这里,是安全防护的第一道防线,也是性能优化的关键节点。
  • 合理的网关架构,可以将单台服务器的处理能力扩展到整个集群,将单点故障风险分散到多个节点,将复杂的安全策略收敛到统一入口。

从运维视角看

  • 证书管理、限流策略、路由规则,都应该在网关层统一配置,避免分散在各个服务。
  • 监控和日志也应该在网关层统一收集,便于分析流量模式、排查问题、审计安全事件。

目标是:在给定的资源和性能约束下,让每一次请求都能被安全、高效、可靠地处理。