现代应用程序的 API 网关模式和最佳实践
API 网关平均处理 83% 的企业流量,充当客户端应用程序的单一入口点。 精心设计的 API 网关可简化客户端-服务器通信、实施安全策略并提供跨所有服务的可观察性。设计不当会成为瓶颈和单点故障。
本指南涵盖了 API 网关架构模式、技术选择以及 Web 应用程序、ERP 系统和电子商务平台的实施最佳实践。
要点
- API 网关集中横切关注点(身份验证、速率限制、日志记录),以消除服务之间的重复
- 网关级别的速率限制可保护后端服务免受流量峰值和滥用的影响
- 当下游服务不健康时,断路器模式可防止级联故障
- 通过网关的 API 版本控制可实现 API 表面的向后兼容演进
核心网关模式
模式 1:请求路由
网关根据 URL 路径、标头或其他请求属性将请求路由到适当的后端服务。
# Nginx as API gateway
upstream api_service {
server api-1:3001;
server api-2:3001;
}
upstream auth_service {
server auth:9000;
}
upstream web_service {
server web:3000;
}
server {
listen 443 ssl;
server_name api.example.com;
location /api/v1/ {
proxy_pass http://api_service;
}
location /auth/ {
proxy_pass http://auth_service;
}
location / {
proxy_pass http://web_service;
}
}
模式 2:身份验证和授权
将身份验证集中在网关处,以避免在每个服务中实施它。
// NestJS middleware for JWT validation at the gateway level
@Injectable()
export class GatewayAuthMiddleware implements NestMiddleware {
constructor(private readonly jwtService: JwtService) {}
async use(req: Request, res: Response, next: NextFunction) {
// Skip public endpoints
if (this.isPublicEndpoint(req.path)) {
return next();
}
const token = this.extractToken(req);
if (!token) {
throw new UnauthorizedException('Missing authentication token');
}
try {
const payload = await this.jwtService.verifyAsync(token);
req['user'] = payload;
next();
} catch {
throw new UnauthorizedException('Invalid token');
}
}
private extractToken(req: Request): string | undefined {
// Check cookie first, then Authorization header
return req.cookies?.ecosire_auth
|| req.headers.authorization?.replace('Bearer ', '');
}
private isPublicEndpoint(path: string): boolean {
const publicPaths = ['/health', '/api/v1/products', '/api/v1/blog'];
return publicPaths.some(p => path.startsWith(p));
}
}
模式 3:速率限制
// Rate limiting configuration per endpoint type
const rateLimits = {
public: { windowMs: 60000, max: 100 }, // 100 req/min for public APIs
authenticated: { windowMs: 60000, max: 500 }, // 500 req/min for authenticated users
admin: { windowMs: 60000, max: 1000 }, // 1000 req/min for admin
webhooks: { windowMs: 60000, max: 50 }, // 50 req/min for webhooks
};
模式 4:断路器
当下游服务出现故障时,断路器可以防止级联故障:
[Closed] --> (failures exceed threshold) --> [Open] --> (timeout expires) --> [Half-Open]
^ |
| (success) |
+--------------------------------------------------------------------<-------+
| (failure) |
| +--------> [Open]
国家:
- 关闭:请求正常通过。跟踪失败计数。
- 打开:所有请求立即失败,无需调用服务。返回缓存/回退响应。
- 半开放:允许一个请求通过。如果成功,则关闭电路。如果失败,重新打开。
模式 5:响应缓存
# Cache GET responses for public endpoints
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;
location /api/v1/products {
proxy_pass http://api_service;
proxy_cache api_cache;
proxy_cache_valid 200 5m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
API 版本控制策略
| 战略 | 网址示例 | 优点 | 缺点 |
|---|---|---|---|
| 网址路径 | 代码0 | 清晰、易于路线 | 网址污染 |
| 查询参数 | 代码0 | 没有更改网址 | 容易错过 |
| 标题 | 代码0 | 干净的网址 | 不易被发现 |
| 内容洽谈 | 代码0 | 基于标准 | 复杂 |
建议:URL 路径版本控制。它是最明确、最可调试且最容易在网关级别路由的。
重大变更与非重大变更
| 更改类型 | 打破? | 行动 |
|---|---|---|
| 向响应添加新字段 | 没有 | 添加到当前版本 |
| 添加新的可选查询参数 | 没有 | 添加到当前版本 |
| 从响应中删除字段 | 是的 | 需要新版本 |
| 更改字段类型 | 是的 | 需要新版本 |
| 更改 URL 路径 | 是的 | 需要新版本 |
| 添加所需参数 | 是的 | 需要新版本 |
网关技术比较
| 技术 | 类型 | 最适合 | 延迟开销 |
|---|---|---|---|
| nginx | 反向代理 | 简单路由、SSL、缓存 | <1毫秒 |
| 孔 | 完整网关 | 插件生态系统,速率限制 | 1-3 毫秒 |
| AWS API 网关 | 管理 | AWS 原生、无服务器 | 5-10 毫秒 |
| 特使 | 服务网格 | Kubernetes、gRPC | <1毫秒 |
| 特拉菲克 | 动态代理 | Docker,自动发现 | 1-2 毫秒 |
对于大多数中小型企业:Nginx 就足够了。它以亚毫秒级开销处理路由、SSL 终止、速率限制和缓存。当您需要高级插件功能(OAuth2、请求转换、分析)时,请升级到 Kong。
网关的可观察性
请求日志记录
log_format gateway '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time '
'$http_x_request_id';
access_log /var/log/nginx/gateway.log gateway;
指标集合
在网关级别跟踪这些指标:
- 请求率(按端点、方法和状态代码)
- 延迟分布(P50、P95、P99)(按端点)
- 错误率(按端点和错误类型划分)
- 客户端达到速率限制
- 缓存命中率(按端点)
- 上游响应时间 与总响应时间
网关的错误处理
一致的错误响应
网关应该规范来自不同后端服务的错误响应:
{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "The requested service is temporarily unavailable",
"requestId": "req_abc123",
"timestamp": "2026-03-16T14:32:01Z"
}
}
重试和超时配置
location /api/ {
proxy_pass http://api_service;
# Timeout configuration
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# Retry on connection errors only (not on 5xx)
proxy_next_upstream error timeout;
proxy_next_upstream_tries 2;
# Custom error pages
error_page 502 503 504 /api-error.json;
}
优雅的降级
当非关键后端服务关闭时,网关可以提供缓存的响应或回退数据,而不是返回错误:
| 服务状态 | 网关行为 |
|---|---|
| 健康 | 正常代理到后端 |
| 慢(延迟 >2 秒) | 返回缓存的响应(如果可用),否则代理 |
| 下降(5xx 错误) | 返回带有 X-Cache-Stale 标头的缓存响应 |
| 向下+无缓存 | 返回 503 状态的后备响应 |
网关安全模式
请求验证
在转发到后端服务之前验证请求结构:
- 拒绝未知内容类型的请求
- 强制每个端点的最大请求正文大小
- 验证所需的标头(API 版本、内容类型)
- 去除可疑标头(逐跳标头、服务器内部标头)
管理端点的 IP 允许列表
location /api/admin/ {
allow 203.0.113.0/24; # Office IP range
allow 10.0.0.0/8; # Internal network
deny all;
proxy_pass http://api_service;
}
请求转换
网关可以在转发之前添加、修改或删除标头:
location /api/ {
proxy_pass http://api_service;
# Add security headers
proxy_set_header X-Request-ID $request_id;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
# Remove internal headers from responses
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
}
常见问题
我们是否需要为单体应用程序提供 API 网关?
是的,但是更简单。即使对于单体应用,Nginx 作为反向代理也提供 SSL 终止、速率限制、静态文件服务和安全标头。您不需要 Kong 或 AWS API Gateway 来构建整体,但您确实需要在互联网和应用程序服务器之间建立一些东西。
我们如何处理 API 网关故障转移?
在云负载均衡器(AWS ALB、Cloudflare)后面运行多个网关实例。如果一个网关实例发生故障,负载均衡器会将流量路由到运行状况良好的实例。对于 Nginx,使用主动健康检查并自动删除不健康的上游。
API 网关应该处理身份验证还是每个服务?
网关应该处理身份验证(验证令牌是否有效)。各个服务应该处理授权(检查经过身份验证的用户是否有权执行特定操作)。这种分离使网关保持轻量级,并允许服务做出细粒度的访问控制决策。
我们如何在 API 网关处处理 CORS?
在网关级别配置 CORS 以避免跨服务重复 CORS 标头。将 Access-Control-Allow-Origin 设置为您的特定前端域(切勿在生产中使用凭据使用 *)。在网关处处理预检 OPTIONS 请求,以减少后端服务的负载。
接下来会发生什么
API 网关是基础设施的前门。将其与监控配对以实现可见性,将其与安全强化配对以进行保护,并与负载测试配对以进行容量规划。
联系 ECOSIRE 获取 API 架构咨询,或浏览我们的 DevOps 指南 获取完整的基础设施路线图。
由 ECOSIRE 发布——帮助企业构建可扩展的 API 基础设施。
作者
ECOSIRE Research and Development Team
在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。