跳到主要内容

API网关详解

API网关是微服务架构中的重要组件,作为系统的统一入口,负责请求路由、负载均衡、认证授权、限流熔断等功能。

核心价值

API网关 = 统一入口 + 服务治理 + 安全控制 + 性能优化

  • 🌐 统一入口:为所有微服务提供统一的访问入口
  • 🔒 安全控制:集中处理认证、授权、加密等安全功能
  • 性能优化:负载均衡、缓存、压缩等性能优化
  • 🛡️ 服务治理:限流、熔断、监控、日志等治理功能

1. API网关核心功能

1.1 请求路由

API网关根据请求的URL、头部信息等将请求路由到相应的后端服务。

Spring Cloud Gateway路由配置
java
1@Configuration
2public class GatewayConfig {
3
4 @Bean
5 public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
6 return builder.routes()
7 // 用户服务路由
8 .route("user-service", r -> r
9 .path("/api/users/**")
10 .uri("lb://user-service"))
11
12 // 订单服务路由
13 .route("order-service", r -> r
14 .path("/api/orders/**")
15 .uri("lb://order-service"))
16
17 // 支付服务路由
18 .route("payment-service", r -> r
19 .path("/api/payments/**")
20 .uri("lb://payment-service"))
21
22 .build();
23 }
24}

1.2 负载均衡

API网关可以在多个服务实例之间分发请求,提高系统的可用性和性能。

负载均衡配置
java
1@Configuration
2public class LoadBalancerConfig {
3
4 @Bean
5 @LoadBalanced
6 public RestTemplate restTemplate() {
7 return new RestTemplate();
8 }
9
10 // 自定义负载均衡策略
11 @Bean
12 public ReactorLoadBalancer<ServiceInstance> userServiceLoadBalancer(
13 Environment environment,
14 LoadBalancerClientFactory loadBalancerClientFactory) {
15
16 String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
17 return new RoundRobinLoadBalancer(
18 loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
19 name);
20 }
21}

1.3 认证授权

API网关可以集中处理认证和授权逻辑,确保只有合法用户才能访问系统。

JWT认证过滤器
java
1@Component
2public class JwtAuthenticationFilter implements GlobalFilter, Ordered {
3
4 private final JwtTokenProvider jwtTokenProvider;
5
6 public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
7 this.jwtTokenProvider = jwtTokenProvider;
8 }
9
10 @Override
11 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
12 ServerHttpRequest request = exchange.getRequest();
13
14 // 跳过不需要认证的路径
15 if (isPublicPath(request.getPath().value())) {
16 return chain.filter(exchange);
17 }
18
19 // 获取Authorization头
20 String authHeader = request.getHeaders().getFirst("Authorization");
21 if (authHeader == null || !authHeader.startsWith("Bearer ")) {
22 return handleUnauthorized(exchange);
23 }
24
25 String token = authHeader.substring(7);
26
27 try {
28 // 验证JWT token
29 if (jwtTokenProvider.validateToken(token)) {
30 // 提取用户信息并添加到请求头
31 String userId = jwtTokenProvider.getUserIdFromToken(token);
32 String userRole = jwtTokenProvider.getUserRoleFromToken(token);
33
34 ServerHttpRequest modifiedRequest = request.mutate()
35 .header("X-User-Id", userId)
36 .header("X-User-Role", userRole)
37 .build();
38
39 return chain.filter(exchange.mutate().request(modifiedRequest).build());
40 } else {
41 return handleUnauthorized(exchange);
42 }
43 } catch (Exception e) {
44 return handleUnauthorized(exchange);
45 }
46 }
47
48 private boolean isPublicPath(String path) {
49 return path.startsWith("/api/auth/") ||
50 path.startsWith("/api/public/") ||
51 path.equals("/health");
52 }
53
54 private Mono<Void> handleUnauthorized(ServerWebExchange exchange) {
55 ServerHttpResponse response = exchange.getResponse();
56 response.setStatusCode(HttpStatus.UNAUTHORIZED);
57 response.getHeaders().add("Content-Type", "application/json");
58
59 String body = "{\"error\":\"Unauthorized\",\"message\":\"Invalid or missing token\"}";
60 DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
61 return response.writeWith(Mono.just(buffer));
62 }
63
64 @Override
65 public int getOrder() {
66 return -100; // 高优先级,在其他过滤器之前执行
67 }
68}

2. 限流与熔断

2.1 限流实现

Redis限流过滤器
java
1@Component
2public class RateLimitFilter implements GlobalFilter, Ordered {
3
4 private final RedisTemplate<String, String> redisTemplate;
5 private final RedisScript<Long> rateLimitScript;
6
7 public RateLimitFilter(RedisTemplate<String, String> redisTemplate) {
8 this.redisTemplate = redisTemplate;
9 this.rateLimitScript = createRateLimitScript();
10 }
11
12 @Override
13 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
14 ServerHttpRequest request = exchange.getRequest();
15 String clientId = getClientId(request);
16 String path = request.getPath().value();
17
18 // 构建限流key
19 String rateLimitKey = "rate_limit:" + clientId + ":" + path;
20
21 // 执行限流检查
22 Long currentRequests = redisTemplate.execute(
23 rateLimitScript,
24 Collections.singletonList(rateLimitKey),
25 "10", // 限制:10次/分钟
26 "60" // 时间窗口:60秒
27 );
28
29 if (currentRequests != null && currentRequests > 10) {
30 return handleRateLimitExceeded(exchange);
31 }
32
33 return chain.filter(exchange);
34 }
35
36 private String getClientId(ServerHttpRequest request) {
37 // 优先使用API Key
38 String apiKey = request.getHeaders().getFirst("X-API-Key");
39 if (apiKey != null) {
40 return "api_key:" + apiKey;
41 }
42
43 // 使用IP地址作为fallback
44 String clientIp = getClientIp(request);
45 return "ip:" + clientIp;
46 }
47
48 private String getClientIp(ServerHttpRequest request) {
49 String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
50 if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
51 return xForwardedFor.split(",")[0].trim();
52 }
53
54 String xRealIp = request.getHeaders().getFirst("X-Real-IP");
55 if (xRealIp != null && !xRealIp.isEmpty()) {
56 return xRealIp;
57 }
58
59 return request.getRemoteAddress() != null ?
60 request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
61 }
62
63 private RedisScript<Long> createRateLimitScript() {
64 String script =
65 "local key = KEYS[1] " +
66 "local limit = tonumber(ARGV[1]) " +
67 "local window = tonumber(ARGV[2]) " +
68 "local current = redis.call('incr', key) " +
69 "if current == 1 then " +
70 " redis.call('expire', key, window) " +
71 "end " +
72 "return current";
73
74 return RedisScript.of(script, Long.class);
75 }
76
77 private Mono<Void> handleRateLimitExceeded(ServerWebExchange exchange) {
78 ServerHttpResponse response = exchange.getResponse();
79 response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
80 response.getHeaders().add("Content-Type", "application/json");
81
82 String body = "{\"error\":\"Rate limit exceeded\",\"message\":\"Too many requests\"}";
83 DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
84 return response.writeWith(Mono.just(buffer));
85 }
86
87 @Override
88 public int getOrder() {
89 return -50;
90 }
91}

2.2 熔断器实现

熔断器过滤器
java
1@Component
2public class CircuitBreakerFilter implements GlobalFilter, Ordered {
3
4 private final CircuitBreakerRegistry circuitBreakerRegistry;
5
6 public CircuitBreakerFilter(CircuitBreakerRegistry circuitBreakerRegistry) {
7 this.circuitBreakerRegistry = circuitBreakerRegistry;
8 }
9
10 @Override
11 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
12 String serviceName = getServiceName(exchange.getRequest());
13 CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceName);
14
15 return circuitBreaker.executeSupplier(() -> chain.filter(exchange))
16 .onErrorResume(Exception.class, ex -> handleCircuitBreakerOpen(exchange, ex));
17 }
18
19 private String getServiceName(ServerHttpRequest request) {
20 String path = request.getPath().value();
21 if (path.startsWith("/api/users")) return "user-service";
22 if (path.startsWith("/api/orders")) return "order-service";
23 if (path.startsWith("/api/payments")) return "payment-service";
24 return "default-service";
25 }
26
27 private Mono<Void> handleCircuitBreakerOpen(ServerWebExchange exchange, Exception ex) {
28 ServerHttpResponse response = exchange.getResponse();
29 response.setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
30 response.getHeaders().add("Content-Type", "application/json");
31
32 String body = "{\"error\":\"Service unavailable\",\"message\":\"Circuit breaker is open\"}";
33 DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
34 return response.writeWith(Mono.just(buffer));
35 }
36
37 @Override
38 public int getOrder() {
39 return 0;
40 }
41}

3. 监控与日志

3.1 请求日志记录

请求日志过滤器
java
1@Component
2@Slf4j
3public class RequestLoggingFilter implements GlobalFilter, Ordered {
4
5 @Override
6 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
7 ServerHttpRequest request = exchange.getRequest();
8 long startTime = System.currentTimeMillis();
9
10 // 记录请求信息
11 String requestId = UUID.randomUUID().toString();
12 exchange.getAttributes().put("requestId", requestId);
13 exchange.getAttributes().put("startTime", startTime);
14
15 log.info("Request started - ID: {}, Method: {}, Path: {}, Client: {}",
16 requestId, request.getMethod(), request.getPath(),
17 getClientIp(request));
18
19 return chain.filter(exchange).then(
20 Mono.fromRunnable(() -> {
21 long endTime = System.currentTimeMillis();
22 long duration = endTime - startTime;
23
24 ServerHttpResponse response = exchange.getResponse();
25 log.info("Request completed - ID: {}, Status: {}, Duration: {}ms",
26 requestId, response.getStatusCode(), duration);
27 })
28 );
29 }
30
31 private String getClientIp(ServerHttpRequest request) {
32 String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
33 if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
34 return xForwardedFor.split(",")[0].trim();
35 }
36 return request.getRemoteAddress() != null ?
37 request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
38 }
39
40 @Override
41 public int getOrder() {
42 return Ordered.HIGHEST_PRECEDENCE;
43 }
44}

4. 配置管理

4.1 动态路由配置

application.yml
yaml
1spring:
2 cloud:
3 gateway:
4 routes:
5 - id: user-service
6 uri: lb://user-service
7 predicates:
8 - Path=/api/users/**
9 filters:
10 - StripPrefix=2
11 - AddRequestHeader=X-Service-Name, user-service
12 - name: RequestRateLimiter
13 args:
14 redis-rate-limiter.replenishRate: 10
15 redis-rate-limiter.burstCapacity: 20
16 key-resolver: "#{@userKeyResolver}"
17
18 - id: order-service
19 uri: lb://order-service
20 predicates:
21 - Path=/api/orders/**
22 filters:
23 - StripPrefix=2
24 - AddRequestHeader=X-Service-Name, order-service
25 - name: CircuitBreaker
26 args:
27 name: order-service-cb
28 fallbackUri: forward:/fallback/orders
29
30 - id: payment-service
31 uri: lb://payment-service
32 predicates:
33 - Path=/api/payments/**
34 filters:
35 - StripPrefix=2
36 - AddRequestHeader=X-Service-Name, payment-service
37 - name: Retry
38 args:
39 retries: 3
40 statuses: BAD_GATEWAY,GATEWAY_TIMEOUT
41 backoff:
42 firstBackoff: 10ms
43 maxBackoff: 50ms
44 factor: 2
45
46 # Redis配置(用于限流)
47 redis:
48 host: localhost
49 port: 6379
50 timeout: 2000ms
51 lettuce:
52 pool:
53 max-active: 8
54 max-idle: 8
55 min-idle: 0
56
57# 熔断器配置
58resilience4j:
59 circuitbreaker:
60 instances:
61 user-service-cb:
62 slidingWindowSize: 10
63 minimumNumberOfCalls: 5
64 failureRateThreshold: 50
65 waitDurationInOpenState: 30s
66 permittedNumberOfCallsInHalfOpenState: 3
67 order-service-cb:
68 slidingWindowSize: 20
69 minimumNumberOfCalls: 10
70 failureRateThreshold: 60
71 waitDurationInOpenState: 60s
72 payment-service-cb:
73 slidingWindowSize: 15
74 minimumNumberOfCalls: 8
75 failureRateThreshold: 40
76 waitDurationInOpenState: 45s
77
78# 监控配置
79management:
80 endpoints:
81 web:
82 exposure:
83 include: health,info,metrics,prometheus
84 endpoint:
85 health:
86 show-details: always
87 metrics:
88 export:
89 prometheus:
90 enabled: true

通过本章的学习,你应该已经深入理解了API网关的核心概念、实现方案和最佳实践。API网关是微服务架构的重要基础设施,合理使用网关可以显著提高系统的安全性、可维护性和可扩展性。在实际项目中,要根据业务需求选择合适的网关方案,并注重性能优化和监控运维。

评论