适用人群:后端开发者、架构师
学习时长:约2-3天
技术:Nginx / Kong / Spring Cloud Gateway
适用场景:微服务架构、API管理
一、API网关是什么?
API网关是系统的统一入口,负责请求路由、认证、限流、日志等横切关注点。
| 功能 | 说明 |
|---|---|
| 路由转发 | 将请求转发到对应的后端服务 |
| 负载均衡 | 将流量分发到多个服务实例 |
| 认证授权 | 统一身份验证 |
| 限流熔断 | 保护后端服务 |
| 日志监控 | 记录请求日志 |
| 协议转换 | HTTP ↔ gRPC |
| 缓存 | 缓存热点数据 |
二、Nginx 作为API网关
2.1 基础配置
# 定义上游服务
upstream user-service {
server 192.168.1.10:8081;
server 192.168.1.11:8081;
}
upstream order-service {
server 192.168.1.20:8082;
server 192.168.1.21:8082;
}
upstream product-service {
server 192.168.1.30:8083;
}
# 限流配置
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
server {
listen 80;
server_name api.example.com;
# 全局限流
limit_req zone=api burst=200 nodelay;
# 用户服务
location /api/users/ {
proxy_pass http://user-service;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-ID $request_id;
}
# 订单服务
location /api/orders/ {
proxy_pass http://order-service;
proxy_set_header X-Real-IP $remote_addr;
}
# 商品服务
location /api/products/ {
proxy_pass http://product-service;
proxy_set_header X-Real-IP $remote_addr;
}
# 登录接口限流(更严格)
location /api/auth/login {
limit_req zone=login burst=3 nodelay;
proxy_pass http://user-service;
}
}
2.2 负载均衡策略
# 轮询(默认)
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 加权轮询
upstream backend {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=2;
}
# IP Hash(会话保持)
upstream backend {
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 最少连接
upstream backend {
least_conn;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
三、Kong API网关
3.1 安装
# Docker安装
docker run -d --name kong-database \
-p 5432:5432 \
-e KONG_DATABASE=postgres \
-e KONG_PG_PASSWORD=kong \
postgres:13
docker run --rm --network=host \
kong:latest kong migrations bootstrap
docker run -d --name kong \
--network=host \
-e KONG_DATABASE=postgres \
-e KONG_PG_HOST=localhost \
-e KONG_PG_PASSWORD=kong \
-e KONG_PROXY_LISTEN=0.0.0.0:8000 \
-e KONG_ADMIN_LISTEN=0.0.0.0:8001 \
kong:latest
3.2 配置服务和路由
# 添加服务
curl -X POST http://localhost:8001/services/ \
--data "name=user-service" \
--data "url=http://192.168.1.10:8081"
# 添加路由
curl -X POST http://localhost:8001/services/user-service/routes \
--data "name=user-routes" \
--data "paths[]=/api/users" \
--data "methods[]=GET" \
--data "methods[]=POST"
# 添加限流插件
curl -X POST http://localhost:8001/services/user-service/plugins \
--data "name=rate-limiting" \
--data "config.second=100" \
--data "config.policy=local"
# 添加认证插件
curl -X POST http://localhost:8001/services/user-service/plugins \
--data "name=jwt"
四、Spring Cloud Gateway(Java)
# application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=0
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=0
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- StripPrefix=0
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200
// 自定义认证过滤器
@Component
public class AuthGatewayFilter implements GatewayFilterFactory<AuthGatewayFilter.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证token
try {
// JWT验证逻辑
String userId = verifyToken(token.substring(7));
// 将用户信息添加到请求头
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(request).build());
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
};
}
@Override
public Class<Config> getConfigClass() {
return Config.class;
}
public static class Config {
// 配置属性
}
}
五、网关安全
5.1 JWT认证
# Nginx + Lua实现JWT验证
location /api/ {
access_by_lua_block {
local jwt = require "resty.jwt"
local auth_header = ngx.req.get_headers()["Authorization"]
if not auth_header then
ngx.status = 401
ngx.say('{"code": 401, "message": "未登录"}')
return ngx.exit(401)
end
local token = string.match(auth_header, "Bearer%s+(.+)")
local jwt_obj = jwt:verify("your-secret-key", token)
if not jwt_obj.verified then
ngx.status = 401
ngx.say('{"code": 401, "message": "token无效"}')
return ngx.exit(401)
end
ngx.req.set_header("X-User-Id", jwt_obj.payload.sub)
}
proxy_pass http://backend;
}
5.2 CORS配置
# Nginx CORS配置
location /api/ {
# CORS头
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
# 预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://backend;
}
六、监控与日志
# 自定义日志格式
log_format gateway '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time '
'$request_id';
access_log /var/log/nginx/gateway.log gateway;
学习建议
- 先用Nginx实现基本网关,理解核心概念
- 学习Kong或APISIX,生产级网关
- 掌握认证和限流,安全是核心
- 配置监控和日志,可观测性很重要
- 理解服务发现,动态路由