哈喽,大家好!今天我们来聊一个在微服务架构里非常热门的话题:如何使用 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_service和order_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的内部location。internal指令意味着这个地址不能被外部直接访问,只能由 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 就会直接将这个状态码返回给客户端,拒绝访问。
- 如果返回其他状态码,则被视为错误。
- 如果认证服务返回 2xx 状态码(成功),Nginx 就会继续处理原始请求,将其转发给
通过这种方式,我们巧妙地将认证逻辑从业务服务中剥离出来,集中在 API 网关和认证服务中处理,大大简化了各个微服务的代码。
案例总结
通过以上三个步骤,我们已经成功地使用 Nginx 搭建了一个具备核心功能的 API 网关:
- 智能路由:能够根据 URL 路径将请求准确地分发到后端的不同微服务。
- 安全限流:能够保护后端服务,防止因流量突增而导致的系统崩溃。
- 统一认证:通过与认证服务配合,实现了对 API 的安全访问控制。
这只是 Nginx 作为 API 网关的冰山一角。Nginx 还提供了诸如 SSL/TLS 终端、日志记录、请求/响应转换、缓存等众多高级功能,你可以根据自己的业务需求,继续探索和配置。
希望这篇教程能帮助你快速上手,使用 Nginx 构建一个高效、稳定、安全的 API 网关。祝你编码愉快!