跳到主要内容

API 网关

API 网关是微服务架构中的重要组件,它作为系统的统一入口,负责请求路由、负载均衡、权限校验、日志记录等工作。

为什么需要 API 网关?

1. 统一入口

在没有网关的情况下,客户端需要知道每个微服务的地址:

无网关的架构(客户端直接调用):
┌──────────┐ ┌──────────┐
│ 客户端 │────►│ 用户服务 │
└──────────┘ └──────────┘
┌──────────┐ ┌──────────┐
│ 客户端 │────►│ 订单服务 │
└──────────┘ └──────────┘
┌──────────┐ ┌──────────┐
│ 客户端 │────►│ 商品服务 │
└──────────┘ └──────────┘

问题:
1. 客户端需要管理多个服务端点
2. 跨域问题
3. 认证授权逻辑重复
4. 难以统一监控和日志

2. 使用 API 网关

有网关的架构:
┌──────────┐
│ 客户端 │
└────┬─────┘


┌─────────────────────┐
│ API 网关 │ ← 统一入口
│ (Gateway) │
└────┬────────┬────────┘
│ │ │
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│用户服务 ││订单服务 ││商品服务 │
└────────┘└────────┘└────────┘

优势:
1. 客户端只需知道网关地址
2. 统一认证授权
3. 统一日志和监控
4. 减少客户端与服务的耦合

Spring Cloud Gateway 简介

Spring Cloud Gateway 是 Spring 官方开发的网关框架,基于 WebFlux(响应式编程)和 Project Reactor。

特点

  1. 基于 Spring Framework 5:使用函数式编程
  2. 基于 Project Reactor:完全异步非阻塞
  3. 动态路由:支持配置动态更新
  4. 内置 Predicates:支持多种路由匹配条件
  5. 内置 Filters:支持请求和响应的过滤

Spring Cloud Gateway 工作原理

请求流程:

┌──────────────┐
│ 客户端 │
└──────┬───────┘
│ HTTP/HTTPS

┌──────────────────────────────────────────────────┐
│ Gateway Handler Mapping │
│ (根据 uri 匹配路由规则) │
└──────────────────────┬───────────────────────────┘


┌──────────────────────────────────────────────────┐
│ Gateway Web Handler │
│ (执行前置过滤器链) │
└──────────────────────┬───────────────────────────┘


┌──────────────────────────────────────────────────┐
│ Filter Chain │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Filter1 │→ │ Filter2 │→ │ Filter3 │→ ... │
│ │ (认证) │ │ (日志) │ │ (限流) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────┬───────────────────────────┘


┌──────────────────────────────────────────────────┐
│ Proxy Handler │
│ (转发到下游服务) │
└──────────────────────┬───────────────────────────┘


┌──────────────┐
│ 下游服务 │
└──────────────┘

快速开始

1. 引入依赖

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 如果需要服务发现 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>

2. 配置文件

server:
port: 8080

spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true # 启用服务发现
lower-case-service-id: true # 服务名小写
routes:
- id: user-service
uri: lb://user-service # lb 表示负载均衡
predicates:
- Path=/user/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**

eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

3. 启动类

@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

路由配置详解

路由(Route)

路由是网关的基本组成单元,包含以下属性:

  • id:路由唯一标识
  • uri:目标服务地址
  • predicates:路由匹配条件
  • filters:过滤器
spring:
cloud:
gateway:
routes:
- id: my-route
uri: http://localhost:8081
predicates:
- Path=/api/**
filters:
- StripPrefix=1

谓词(Predicate)

Spring Cloud Gateway 内置多种谓词:

1. Path 路径匹配

predicates:
- Path=/user/**
- Path=/order/{id}

2. Method HTTP 方法

predicates:
- Method=GET,POST

3. Header 请求头

predicates:
- Header=X-Request-Id, \d+

4. Query 查询参数

predicates:
- Query=name
- Query=name, zhang.* # 正则匹配

5. After / Before / Between 时间

predicates:
- After=2024-01-01T00:00:00.000+08:00[Asia/Shanghai]
predicates:
- Cookie=name, zhangsan

7. 组合多个谓词

spring:
cloud:
gateway:
routes:
- id: combine-predicates
uri: lb://user-service
predicates:
- Path=/user/**
- Method=GET
- Header=Authorization, Bearer.*

过滤器(Filter)

过滤器可以在请求前后执行自定义逻辑。

1. 内置过滤器

filters:
- StripPrefix=1 # 去掉路径前缀
- AddRequestHeader=X-Request-Id, ${UUID} # 添加请求头
- AddResponseHeader=X-Response-Id, ${UUID} # 添加响应头
- RemoveRequestHeader=X-Remove # 移除请求头
- SetStatus=200 # 设置响应状态
- SetResponseHeader=Content-Type, application/json # 设置响应头
- RedirectTo=302, https://example.com # 重定向

2. 自定义过滤器

// 全局过滤器
@Component
public class GlobalFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 获取请求
ServerHttpRequest request = exchange.getRequest();

// 记录日志
System.out.println("请求路径: " + request.getURI());

// 业务逻辑
String token = request.getHeaders().getFirst("Authorization");

// 继续执行过滤器链
return chain.filter(exchange);
}

@Override
public int getOrder() {
return -100; // 优先级,数字越小越先执行
}
}
// 局部过滤器
@Component
public class CustomGatewayFilterFactory
extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {

public CustomGatewayFilterFactory() {
super(Config.class);
}

@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 前置逻辑
if (config.isEnabled()) {
System.out.println("前置过滤器执行");
}

// 执行后续过滤器
return chain.filter(exchange).then(
// 后置逻辑
Mono.fromRunnable(() -> {
if (config.isEnabled()) {
System.out.println("后置过滤器执行");
}
})
);
};
}

public static class Config {
private boolean enabled = true;

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

服务认证与授权

1. JWT 认证

@Component
public class JwtAuthenticationFilter implements GlobalFilter {

@Autowired
private JwtUtils jwtUtils;

@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
String token = getTokenFromRequest(exchange.getRequest());

if (token != null && jwtUtils.validateToken(token)) {
// 验证通过,将用户信息添加到请求属性
String userId = jwtUtils.getUserIdFromToken(token);
ServerHttpRequest request = exchange.getRequest()
.mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(request).build());
}

// 验证失败,返回 401
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}

private String getTokenFromRequest(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}

2. 权限校验

@Component
public class PermissionFilter implements GlobalFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");

// 检查用户是否有权限访问该路径
if (!hasPermission(userId, path)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}

return chain.filter(exchange);
}

private boolean hasPermission(String userId, String path) {
// 实际业务中查询权限
return true;
}
}

限流

使用 Redis 进行限流

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
</dependencies>
spring:
cloud:
gateway:
redis:
rate-limiter:
replenish-rate: 1 # 每秒补充令牌数
burst-capacity: 10 # 令牌桶容量
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter:
replenish-rate: 10
burst-capacity: 20
requested-retokens: 1

自定义限流器

@Component
public class CustomRateLimiterGatewayFilterFactory
extends AbstractGatewayFilterFactory<CustomRateLimiterGatewayFilterFactory.Config> {

@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String key = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
int count = getCurrentCount(key);

if (count > config.getMaxRequests()) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}

incrementCount(key);
return chain.filter(exchange);
};
}

// 实现限流逻辑
private int getCurrentCount(String key) { return 0; }
private void incrementCount(String key) { }

public static class Config {
private int maxRequests = 100;

public int getMaxRequests() { return maxRequests; }
public void setMaxRequests(int maxRequests) { this.maxRequests = maxRequests; }
}
}

熔断与降级

使用 Resilience4j 集成

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
</dependencies>
spring:
cloud:
gateway:
default-filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
@RestController
public class FallbackController {

@GetMapping("/fallback")
public Map<String, Object> fallback() {
Map<String, Object> result = new HashMap<>();
result.put("code", 503);
result.put("message", "服务暂时不可用,请稍后重试");
return result;
}
}

跨域配置

@Configuration
public class CorsConfig {

@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setMaxAge(3600L);

UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);

return new CorsWebFilter(source);
}
}

高可用

多实例部署

┌─────────────────────┐
│ 负载均衡器 │
│ (Nginx/F5/LB) │
└──────────┬──────────┘

┌──────┴──────┐
│ │
▼ ▼
┌────────┐ ┌────────┐
│Gateway1│ │Gateway2│
│ 8080 │ │ 8081 │
└────────┘ └────────┘

最佳实践

  1. 路由设计:合理规划路由粒度,避免路由过多
  2. 限流配置:根据服务能力配置合适的限流规则
  3. 超时配置:合理设置超时时间,避免请求堆积
  4. 监控告警:监控网关的请求量、响应时间、错误率
  5. 日志记录:记录请求日志,便于问题排查

小结

本章主要介绍了:

  1. API 网关的作用:统一入口、认证授权、日志监控
  2. Spring Cloud Gateway:Spring 官方网关框架
  3. 路由配置:路由、谓词、过滤器
  4. 认证授权:JWT 认证、权限校验
  5. 限流与熔断:保护后端服务
  6. 高可用:多实例部署

API 网关是微服务架构的统一入口,是客户端与服务端之间的桥梁,合理使用网关可以大大提高系统的可维护性和安全性。