Nginx 作为 API 网关 (API Gateway) 的设置教程


哈喽,大家好!今天我们来聊一个在微服务架构里非常热门的话题:如何使用 Nginx 来搭建一个 API 网关。这篇教程会从零开始,用最直接、最口语化的方式,带你一步步配置 Nginx,让它成为你微服务架构的“守门员”。不管你是初学者还是有一定经验的开发者,相信这篇文章都能让你有所收获。

什么是 API 网关?为什么我们需要它?

在如今流行的微服务架构中,一个大的应用会被拆分成很多个小的、独立的服务。这样一来,每个服务都可以独立开发、部署和扩展,非常灵活。但问题也随之而来:客户端(比如手机 App 或者网页)怎么去调用这些散落在各处的服务呢?难道要让客户端记住每个服务的地址吗?这显然不现实,而且非常难以维护。

API 网-关(API Gateway)就是为了解决这个问题而生的。它就像是所有后端微服务的统一入口,客户端的所有请求都先经过它。 API 网关会根据请求的路径或者其他信息,把请求转发给对应的微服务。

使用 API 网关的好处多多:

  • 简化客户端调用:客户端只需要知道 API 网关这一个地址就够了。
  • 统一处理通用功能:像用户认证、权限校验、限流、日志监控这些功能,都可以在网关层统一处理,而不用在每个微服务里都实现一遍。
  • 提高安全性:网关可以作为一道安全屏障,保护后端的微服务不直接暴露在公网。
  • 方便监控和分析:所有流量都经过网关,我们可以很方便地在这里收集日志和监控数据。

而 Nginx,作为一个以高性能、高稳定性和丰富功能著称的反向代理服务器,天然就非常适合用来做 API 网关。

准备工作

在开始之前,你需要确保你的系统上已经安装了 Nginx。如果你还没安装,可以参考 Nginx 官方网站的教程进行安装。本教程将以一个常见的场景为例:我们有两个后端微服务,一个是“用户服务”,另一个是“订单服务”。

  • 用户服务 (user-service): 运行在 http://localhost:8001,提供 /users/* 相关的 API。
  • 订单服务 (order-service): 运行在 http://localhost:8002,提供 /orders/* 相关的 API。

我们的目标是,通过 Nginx 网关,将所有 /api/users/ 开头的请求转发给用户服务,将所有 /api/orders/ 开头的请求转发给订单服务。

Step 1: 基础路由配置

首先,我们来做一个最基础的请求转发配置。找到你的 Nginx 配置文件,通常在 /etc/nginx/nginx.conf 或者 /etc/nginx/conf.d/default.conf。我们建议在 conf.d 目录下创建一个新的配置文件,比如 api_gateway.conf,这样更容易管理。

# /etc/nginx/conf.d/api_gateway.conf

# 定义后端服务的地址
upstream user_service {
    server localhost:8001;
}

upstream order_service {
    server localhost:8002;
}

server {
    listen 80; # 网关监听 80 端口
    server_name api.yourdomain.com; # 你的网关域名

    # 转发到用户服务的规则
    location /api/users/ {
        proxy_pass http://user_service/;
    }

    # 转发到订单服务的规则
    location /api/orders/ {
        proxy_pass http://order_service/;
    }
}

代码解析

  • upstream:这个指令用来定义一组后端服务器。我们为 user_serviceorder_service 分别定义了一个 upstream 块。这样做的好处是,如果你的某个服务有多个实例,可以直接在 upstream 块里添加,Nginx 会自动进行负载均衡。
  • server:定义了一个虚拟主机,我们的网关配置就写在这个块里面。
  • listen 80:让 Nginx 监听 80 端口,接收 HTTP 请求。
  • location:这是 Nginx 配置中非常核心的部分,它会根据请求的 URL 路径来匹配规则。
    • location /api/users/ 会匹配所有以 /api/users/ 开头的请求。
    • proxy_pass http://user_service/:这行代码是关键,它告诉 Nginx 把匹配到的请求转发到我们之前定义的 user_service 这个 upstream 上。

配置好之后,别忘了重新加载 Nginx 使配置生效:sudo nginx -s reload

现在,当你访问 http://api.yourdomain.com/api/users/1 时,Nginx 就会把这个请求转发到 http://localhost:8001/1。同理,访问 http://api.yourdomain.com/api/orders/123 会被转发到 http://localhost:8002/123

Step 2: 实现 API 限流 (Rate Limiting)

为了保护我们的后端服务不被恶意的请求拖垮,限流是一个非常重要的功能。 Nginx 提供了非常简单且强大的限流模块。

我们来修改一下刚才的配置,增加一个全局的限流规则:限制同一个 IP 地址每秒钟只能请求 10 次。

# /etc/nginx/conf.d/api_gateway.conf

# 定义限流规则
# $binary_remote_addr: 基于客户端 IP 地址进行限流
# zone=api_limit:10m: 创建一个名为 api_limit,大小为 10M 的内存区域来存储 IP 地址和它们的请求频率
# rate=10r/s: 允许的平均速率为每秒 10 个请求
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

upstream user_service {
    server localhost:8001;
}

upstream order_service {
    server localhost:8002;
}

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

    # 在 server 块中应用限流规则
    limit_req zone=api_limit burst=20 nodelay;

    location /api/users/ {
        proxy_pass http://user_service/;
    }

    location /api/orders/ {
        proxy_pass http://order_service/;
    }
}

代码解析

  • limit_req_zone:这个指令定义了限流的规则。 我们使用客户端的 IP 地址 ($binary_remote_addr) 作为限流的依据,设置了一个 10MB 的共享内存区域来存储访问信息,并限制平均速率为每秒 10 个请求。
  • limit_req:这个指令在我们想要应用限流的地方(这里是整个 server 块)启用规则。
    • zone=api_limit:指定使用我们刚才定义的 api_limit 规则。
    • burst=20:这个参数非常有用,它允许客户端在短时间内超过设定的速率,最多可以“突发”20个请求。这有助于应对正常的流量波动,提高用户体验。
    • nodelay:配合 burst 使用,表示对于突发的请求,Nginx 会立即处理,而不会延迟它们。

再次 sudo nginx -s reload 后,你的 API 网关就具备了基础的防刷能力。如果某个 IP 的请求过于频繁,Nginx 会返回 503 Service Temporarily Unavailable 错误。

Step 3: 实现用户认证 (Authentication)

一个合格的 API 网关必须要有认证功能,确保只有合法的用户才能访问受保护的资源。目前最主流的认证方式之一是基于 JSON Web Tokens (JWT)。

Nginx 开源版本身不直接支持 JWT 校验,但我们可以通过一个小技巧来实现:利用 auth_request 模块将认证逻辑委托给一个专门的“认证服务”。

假设我们有一个认证服务 auth-service 运行在 http://localhost:8003/validate。当收到请求时,它会检查请求头中的 Authorization 字段,如果 JWT 令牌有效,就返回 200 OK,否则返回 401 Unauthorized

下面是我们的 Nginx 配置:

# /etc/nginx/conf.d/api_gateway.conf

# ... (之前的限流和 upstream 配置) ...
upstream auth_service {
    server localhost:8003;
}

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

    limit_req zone=api_limit burst=20 nodelay;

    # 定义一个内部 location 用于认证请求
    location /auth {
        internal; # 这个 location 只能被内部请求访问
        proxy_pass http://auth_service/validate;
        proxy_pass_request_body off; # 不需要发送请求体给认证服务
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }

    # 保护用户服务
    location /api/users/ {
        auth_request /auth; # 在这里启用认证
        proxy_pass http://user_service/;
    }

    # 订单服务同样需要认证
    location /api/orders/ {
        auth_request /auth;
        proxy_pass http://order_service/;
    }

    # 假设我们有一个公开的 API,比如 /api/public/
    location /api/public/ {
        # 这里没有 auth_request,所以不需要认证
        proxy_pass http://some_public_service/;
    }
}

代码解析

  • location /auth:我们定义了一个名为 /auth 的内部 locationinternal 指令意味着这个地址不能被外部直接访问,只能由 Nginx 内部的其他指令(比如 auth_request)调用。
  • proxy_pass http://auth_service/validate:将认证请求转发给我们的 auth_service
  • auth_request /auth:这是实现认证的关键。 当一个请求进入 /api/users/ 这个 location 时,Nginx 会先暂停这个请求,然后向 /auth 发送一个子请求。
    • 如果认证服务返回 2xx 状态码(成功),Nginx 就会继续处理原始请求,将其转发给 user_service
    • 如果认证服务返回 401 或 403,Nginx 就会直接将这个状态码返回给客户端,拒绝访问。
    • 如果返回其他状态码,则被视为错误。

通过这种方式,我们巧妙地将认证逻辑从业务服务中剥离出来,集中在 API 网关和认证服务中处理,大大简化了各个微服务的代码。

案例总结

通过以上三个步骤,我们已经成功地使用 Nginx 搭建了一个具备核心功能的 API 网关:

  1. 智能路由:能够根据 URL 路径将请求准确地分发到后端的不同微服务。
  2. 安全限流:能够保护后端服务,防止因流量突增而导致的系统崩溃。
  3. 统一认证:通过与认证服务配合,实现了对 API 的安全访问控制。

这只是 Nginx 作为 API 网关的冰山一角。Nginx 还提供了诸如 SSL/TLS 终端、日志记录、请求/响应转换、缓存等众多高级功能,你可以根据自己的业务需求,继续探索和配置。

希望这篇教程能帮助你快速上手,使用 Nginx 构建一个高效、稳定、安全的 API 网关。祝你编码愉快!


  目录