Skip to content

API网关

API网关是微服务架构中的关键组件,作为系统的入口点,它管理和路由所有外部客户端请求到适当的微服务。Spring Cloud提供了多种API网关实现,包括Spring Cloud Gateway和旧版的Zuul。

API网关的作用

API网关在微服务架构中扮演着重要角色,提供以下功能:

  1. 请求路由:将客户端请求路由到相应的微服务
  2. API组合:聚合多个微服务的API调用,减少客户端与服务端的通信次数
  3. 协议转换:支持不同协议之间的转换(如HTTP、WebSocket)
  4. 负载均衡:分发请求到不同的服务实例
  5. 认证与授权:集中处理身份验证和权限控制
  6. 限流与熔断:提供流量控制和服务保护机制
  7. 监控与日志:收集请求和响应的监控指标与日志
  8. 缓存:缓存常用的响应数据,减轻后端服务压力

Spring Cloud Gateway 简介

Spring Cloud Gateway是Spring Cloud官方推荐的API网关,基于Spring WebFlux构建,提供非阻塞、响应式的API网关功能。它替代了早期的Zuul网关,提供更好的性能和更丰富的功能。

核心概念

Spring Cloud Gateway有三个核心概念:

  1. 路由(Route):网关的基本构建块,由ID、目标URI、一系列的断言和过滤器组成
  2. 断言(Predicate):Java 8中的Predicate函数,用于匹配HTTP请求中的任何内容
  3. 过滤器(Filter):修改请求和响应的SpringWebFilter,分为Gateway Filter和Global Filter

工作流程

Spring Cloud Gateway的工作流程如下:

  1. 客户端发送请求到API网关
  2. Gateway Handler Mapping确定请求是否与路由匹配(使用断言)
  3. 如果匹配成功,请求发送到Gateway Web Handler
  4. Handler通过特定于请求的过滤器链发送请求
  5. 过滤器可以在请求发送到目标服务前("pre"过滤器)或接收到响应后("post"过滤器)执行逻辑
  6. 代理请求发送到目标微服务
  7. 响应返回到客户端

配置Spring Cloud Gateway

添加依赖

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

如果需要与服务注册中心集成:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

基本配置

使用YAML配置路由:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/users/**
          filters:
            - StripPrefix=1
            
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/orders/**
          filters:
            - StripPrefix=1

在上面的配置中:

  • id:路由的唯一标识符
  • uri:目标服务地址,lb://前缀表示使用负载均衡
  • predicates:断言条件,用于匹配请求
  • filters:过滤器,用于修改请求或响应

使用Java代码配置

除了YAML配置,还可以使用Java代码配置路由:

java
@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service-route", r -> r
                .path("/users/**")
                .filters(f -> f.stripPrefix(1))
                .uri("lb://user-service"))
            .route("order-service-route", r -> r
                .path("/orders/**")
                .filters(f -> f.stripPrefix(1))
                .uri("lb://order-service"))
            .build();
    }
}

断言工厂

Spring Cloud Gateway提供了多种内置的断言工厂,用于匹配HTTP请求的各个方面:

  1. Path:根据请求路径匹配

    yaml
    predicates:
      - Path=/users/{segment},/user/{segment}
  2. Method:根据HTTP方法匹配

    yaml
    predicates:
      - Method=GET,POST
  3. Header:根据请求头匹配

    yaml
    predicates:
      - Header=X-Request-Id, \d+
  4. Query:根据查询参数匹配

    yaml
    predicates:
      - Query=name, value.*
  5. Cookie:根据Cookie匹配

    yaml
    predicates:
      - Cookie=sessionId, \d+
  6. Host:根据主机名匹配

    yaml
    predicates:
      - Host=**.example.org,**.example.com
  7. Weight:基于权重的路由

    yaml
    routes:
      - id: service-v1
        uri: lb://service-v1
        predicates:
          - Path=/service/**
          - Weight=service,8
      - id: service-v2
        uri: lb://service-v2
        predicates:
          - Path=/service/**
          - Weight=service,2
  8. DateTime:根据时间匹配

    yaml
    predicates:
      - After=2023-01-01T00:00:00+08:00[Asia/Shanghai]
      - Before=2023-12-31T23:59:59+08:00[Asia/Shanghai]
      - Between=2023-01-01T00:00:00+08:00[Asia/Shanghai],2023-12-31T23:59:59+08:00[Asia/Shanghai]

过滤器工厂

Spring Cloud Gateway提供了丰富的过滤器工厂,可以修改进出网关的请求和响应:

内置过滤器

  1. AddRequestHeader:添加请求头

    yaml
    filters:
      - AddRequestHeader=X-Request-Id, 123
  2. AddResponseHeader:添加响应头

    yaml
    filters:
      - AddResponseHeader=X-Response-Id, 456
  3. StripPrefix:去除请求路径前缀

    yaml
    filters:
      - StripPrefix=1  # 去除路径中的第一段
  4. PrefixPath:添加请求路径前缀

    yaml
    filters:
      - PrefixPath=/api
  5. RequestRateLimiter:请求限流

    yaml
    filters:
      - name: RequestRateLimiter
        args:
          redis-rate-limiter.replenishRate: 10
          redis-rate-limiter.burstCapacity: 20
          key-resolver: "#{@userKeyResolver}"
  6. Retry:重试机制

    yaml
    filters:
      - name: Retry
        args:
          retries: 3
          statuses: BAD_GATEWAY
          methods: GET,POST
  7. CircuitBreaker:熔断器

    yaml
    filters:
      - name: CircuitBreaker
        args:
          name: myCircuitBreaker
          fallbackUri: forward:/fallback
  8. RewritePath:重写请求路径

    yaml
    filters:
      - RewritePath=/users/(?<segment>.*), /user-service/$\{segment}

自定义过滤器

可以创建自定义的GatewayFilter,用于实现特定的业务逻辑:

java
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {
    
    public CustomGatewayFilterFactory() {
        super(Config.class);
    }
    
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 前置处理
            ServerHttpRequest request = exchange.getRequest();
            
            // 如果配置了追加头
            if (config.isAddHeader()) {
                ServerHttpRequest modifiedRequest = request.mutate()
                    .header("X-Custom-Header", config.getHeaderValue())
                    .build();
                exchange = exchange.mutate().request(modifiedRequest).build();
            }
            
            return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> {
                    // 后置处理
                    ServerHttpResponse response = exchange.getResponse();
                    // 对响应做一些处理
                }));
        };
    }
    
    public static class Config {
        private boolean addHeader;
        private String headerValue;
        
        // getter and setter
    }
}

注册自定义过滤器:

java
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("custom-filter-route", r -> r
            .path("/custom/**")
            .filters(f -> f
                .filter(new CustomGatewayFilter())
                .stripPrefix(1))
            .uri("lb://custom-service"))
        .build();
}

全局过滤器

全局过滤器应用于所有路由,用于实现通用功能:

java
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求
        ServerHttpRequest request = exchange.getRequest();
        
        // 获取认证信息
        String token = request.getHeaders().getFirst("Authorization");
        
        // 验证token
        if (token == null || !isValidToken(token)) {
            // 返回401错误
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        
        // 继续处理请求
        return chain.filter(exchange);
    }
    
    @Override
    public int getOrder() {
        // 设置优先级
        return -1; // 数字越小,优先级越高
    }
    
    private boolean isValidToken(String token) {
        // 验证token的逻辑
        return true; // 实际实现中需要真正验证token
    }
}

高级功能

集成断路器

集成Resilience4j断路器:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

配置断路器过滤器:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/users/**
          filters:
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/user-service

创建fallback处理器:

java
@RestController
@RequestMapping("/fallback")
public class FallbackController {
    
    @GetMapping("/user-service")
    public Mono<Map<String, String>> userServiceFallback() {
        Map<String, String> response = new HashMap<>();
        response.put("status", "error");
        response.put("message", "User service is currently unavailable");
        return Mono.just(response);
    }
}

限流配置

使用Redis实现限流:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

配置限流器:

java
@Configuration
public class RateLimiterConfig {
    
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20);
    }
    
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getHeaders().getFirst("X-User-Id") != null ?
            exchange.getRequest().getHeaders().getFirst("X-User-Id") : 
            exchange.getRequest().getRemoteAddress().getHostName()
        );
    }
}

应用限流器:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: limited-route
          uri: lb://user-service
          predicates:
            - Path=/limited/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1  # 每秒允许处理的请求数
                redis-rate-limiter.burstCapacity: 2  # 每秒最大处理的请求数
                key-resolver: "#{@userKeyResolver}"  # 用于识别限流对象的键解析器

请求体修改

如果需要修改请求体,需要使用ModifyRequestBodyGatewayFilterFactory:

java
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("modify-request-body", r -> r
            .path("/modify/**")
            .filters(f -> f
                .modifyRequestBody(
                    String.class,
                    String.class,
                    (exchange, s) -> Mono.just(s.toUpperCase()))
            )
            .uri("lb://target-service"))
        .build();
}

跨域配置

配置跨域支持:

yaml
spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "https://example.org"
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
            allowedHeaders: "*"
            allowCredentials: true
            maxAge: 3600

或者通过Java配置:

java
@Configuration
public class CorsConfig {
    
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("https://example.org");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        
        return new CorsWebFilter(source);
    }
}

路由断言的组合

可以组合多个断言来创建复杂的路由匹配规则:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: complex-route
          uri: lb://complex-service
          predicates:
            - Path=/complex/**
            - Method=GET
            - Header=X-API-Version, v1
            - Query=debug, true

上面的路由只会匹配同时满足以下条件的请求:

  • 路径以/complex/开头
  • HTTP方法为GET
  • 请求头X-API-Version的值为v1
  • 查询参数debug的值为true

动态路由

Spring Cloud Gateway支持动态刷新路由,可以与Spring Cloud Config或Nacos等配置中心集成,实现路由配置的动态更新。

使用代码动态刷新路由:

java
@RestController
@RequestMapping("/routes")
public class RouteController {
    
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    
    @Autowired
    private ApplicationEventPublisher publisher;
    
    @PostMapping
    public Mono<ResponseEntity<Object>> addRoute(@RequestBody RouteDefinition routeDefinition) {
        return Mono.fromCallable(() -> {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            publisher.publishEvent(new RefreshRoutesEvent(this));
            return ResponseEntity.ok().build();
        });
    }
    
    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Object>> deleteRoute(@PathVariable String id) {
        return Mono.fromCallable(() -> {
            routeDefinitionWriter.delete(Mono.just(id)).subscribe();
            publisher.publishEvent(new RefreshRoutesEvent(this));
            return ResponseEntity.ok().build();
        });
    }
}

监控与日志

Actuator配置

添加Spring Boot Actuator依赖,可以暴露网关监控端点:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置Actuator端点:

yaml
management:
  endpoints:
    web:
      exposure:
        include: gateway,health,info,metrics
  endpoint:
    gateway:
      enabled: true
    health:
      show-details: always

访问网关路由信息:/actuator/gateway/routes

集成Micrometer和Prometheus

添加Micrometer依赖:

xml
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

启用Prometheus端点:

yaml
management:
  endpoints:
    web:
      exposure:
        include: prometheus,health,info,metrics
  metrics:
    export:
      prometheus:
        enabled: true

访问Prometheus指标:/actuator/prometheus

请求日志

配置日志级别以查看更多请求细节:

yaml
logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    reactor.netty: DEBUG

性能优化

  1. 合理配置线程池:调整Netty工作线程数

    yaml
    spring:
      reactor:
        netty:
          worker:
            count: 16  # 默认为CPU核心数*2
  2. 启用HTTP/2:提高性能和减少连接数

    yaml
    server:
      http2:
        enabled: true
  3. 启用响应式缓存:缓存常用响应

    java
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("cached-route", r -> r
                .path("/cache/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .cache(c -> c
                        .timeToLive(Duration.ofMinutes(10))
                        .cacheSize(1000)))
                .uri("lb://cacheable-service"))
            .build();
    }
  4. 使用WebClient连接池:优化后端服务调用

    java
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create()
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .responseTimeout(Duration.ofSeconds(5))
                    .pool(ConnectionProvider.fixed("custom", 50, 10000))))
            .build();
    }

生产环境部署

高可用部署

为确保网关的高可用性,应考虑以下几点:

  1. 多实例部署:部署多个网关实例,搭配负载均衡器(如Nginx、HAProxy)
  2. 健康检查:实现健康检查端点,确保负载均衡器能够识别不健康的实例
  3. 会话保持:如果必要,配置会话亲和性以保持用户会话

安全配置

  1. HTTPS配置:启用HTTPS保障传输安全

    yaml
    server:
      ssl:
        key-store: classpath:keystore.jks
        key-store-password: password
        key-store-type: JKS
        key-alias: tomcat
        enabled: true
  2. 安全头部:添加安全相关响应头

    yaml
    spring:
      cloud:
        gateway:
          default-filters:
            - AddResponseHeader=X-Content-Type-Options, nosniff
            - AddResponseHeader=X-Frame-Options, DENY
            - AddResponseHeader=X-XSS-Protection, 1; mode=block
  3. 安全策略:实现合适的认证、授权策略,如OAuth2、JWT

常见问题及解决方案

路由不匹配

问题:请求没有被路由到正确的服务 解决方案

  • 检查路由配置和断言条件
  • 启用DEBUG日志观察路由匹配过程
  • 使用Actuator检查已注册的路由

性能问题

问题:网关性能不佳 解决方案

  • 检查后端服务响应时间
  • 优化Netty线程池配置
  • 使用Micrometer监控性能指标
  • 考虑增加网关实例
  • 实现响应缓存

内存泄漏

问题:网关服务内存持续增长 解决方案

  • 检查WebClient连接池配置
  • 确保正确处理响应式流
  • 使用JVM监控工具检查内存使用情况
  • 设置合理的JVM内存限制

与其他组件集成

与Spring Cloud Config集成

集成配置中心,实现动态路由配置:

yaml
spring:
  cloud:
    config:
      uri: http://config-server:8888
      name: gateway
      profile: ${spring.profiles.active}

与Spring Security集成

添加Spring Security依赖:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

配置OAuth2资源服务器:

java
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange()
                .pathMatchers("/public/**").permitAll()
                .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
                .jwt();
        return http.build();
    }
}

与Spring Cloud Sleuth集成

添加分布式追踪支持:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

配置Sleuth和Zipkin:

yaml
spring:
  sleuth:
    sampler:
      probability: 1.0  # 采样率,生产环境建议降低
  zipkin:
    base-url: http://zipkin-server:9411

总结

Spring Cloud Gateway提供了强大而灵活的API网关解决方案,通过路由、断言和过滤器的组合,可以满足各种微服务架构的需求。作为微服务架构的入口点,它不仅处理请求路由,还承担了认证、限流、监控等重要任务。

通过本文的学习,你应该能够:

  • 理解API网关在微服务架构中的作用
  • 掌握Spring Cloud Gateway的核心概念和工作原理
  • 学会配置路由、断言和过滤器
  • 实现高级功能如限流、熔断、跨域等
  • 了解网关的监控、优化和生产部署最佳实践

在实际应用中,应根据系统的规模和需求,选择合适的配置,并关注性能、安全和可用性等方面,确保API网关能够高效可靠地服务于整个微服务架构。