大家好,我是小悟。
一、API Gateway概述
什么是API Gateway?
API Gateway(API网关)是一个服务器端组件,作为客户端与后端微服务之间的单一入口点。它负责请求路由、组合、协议转换以及跨领域功能处理。
主要功能:
- 请求路由:将客户端请求路由到对应的后端服务
- 负载均衡:在多个服务实例间分发请求
- 身份验证和授权:统一处理安全认证
- 限流和熔断:防止服务过载
- 监控和日志:集中收集请求指标
- 协议转换:处理不同协议间的转换
- 缓存:缓存响应以提升性能
二、Spring Cloud Gateway整合步骤
环境要求
- JDK 11+
- Spring Boot 2.7+
- Maven 3.6+
步骤1:创建父工程
<!-- pom.xml --> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>gateway-demo</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.14</version> <relativePath/> </parent> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.8</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <modules> <module>api-gateway</module> </modules> </project>
步骤2:创建Gateway服务
<!-- api-gateway/pom.xml --> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>gateway-demo</artifactId> <groupId>com.example</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>api-gateway</artifactId> <dependencies> <!-- Spring Cloud Gateway --> <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> <!-- 配置中心 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- 监控 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 安全 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies> </project>
步骤3:主启动类
// ApiGatewayApplication.java package com.example.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ApiGatewayApplication { public static void main(String[] args) { SpringApplication.run(ApiGatewayApplication.class, args); } }
步骤4:基础配置
# application.yml server: port: 8080 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true # 启用服务发现 lower-case-service-id: true routes: # 用户服务路由 - id: user-service uri: lb://USER-SERVICE predicates: - Path=/api/users/** filters: - StripPrefix=1 - name: CircuitBreaker args: name: userService fallbackUri: forward:/fallback/user # 商品服务路由 - id: product-service uri: lb://PRODUCT-SERVICE predicates: - Path=/api/products/** filters: - StripPrefix=1 - AddRequestHeader=X-Request-From, gateway # 订单服务路由 - id: order-service uri: lb://ORDER-SERVICE predicates: - Path=/api/orders/** filters: - StripPrefix=1 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒10个请求 redis-rate-limiter.burstCapacity: 20 # 最大突发容量20 key-resolver: "#{@userKeyResolver}" # 直接路由示例 - id: baidu-route uri: https://www.baidu.com predicates: - Path=/baidu/** # 全局过滤器配置 default-filters: - AddResponseHeader=X-Response-Time, ${spring.application.name} # 负载均衡配置 loadbalancer: retry: enabled: true # 熔断器配置 resilience4j: circuitbreaker: instances: userService: slidingWindowSize: 10 failureRateThreshold: 50 waitDurationInOpenState: 10000 # 监控端点 management: endpoints: web: exposure: include: health,info,gateway endpoint: gateway: enabled: true
步骤5:自定义过滤器
// JwtAuthenticationFilter.java package com.example.gateway.filter; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; @Component public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAuthenticationFilter.Config> { @Value("${jwt.secret}") private String jwtSecret; public JwtAuthenticationFilter() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { String path = exchange.getRequest().getURI().getPath(); // 跳过认证的路径 if (config.getWhiteList().stream().anyMatch(path::startsWith)) { return chain.filter(exchange); } // 获取token String token = exchange.getRequest() .getHeaders() .getFirst(HttpHeaders.AUTHORIZATION); if (token == null || !token.startsWith("Bearer ")) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } try { // 验证JWT Claims claims = Jwts.parser() .setSigningKey(jwtSecret) .parseClaimsJws(token.substring(7)) .getBody(); // 添加用户信息到header exchange.getRequest().mutate() .header("X-User-Id", claims.getSubject()) .header("X-User-Roles", claims.get("roles", String.class)) .build(); } catch (Exception e) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } return chain.filter(exchange); }; } public static class Config { private java.util.List<String> whiteList = new java.util.ArrayList<>(); public java.util.List<String> getWhiteList() { return whiteList; } public void setWhiteList(java.util.List<String> whiteList) { this.whiteList = whiteList; } } }
步骤6:全局过滤器
// GlobalLoggingFilter.java package com.example.gateway.filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class GlobalLoggingFilter implements GlobalFilter, Ordered { private static final Logger logger = LoggerFactory.getLogger(GlobalLoggingFilter.class); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { long startTime = System.currentTimeMillis(); return chain.filter(exchange).then(Mono.fromRunnable(() -> { long duration = System.currentTimeMillis() - startTime; logger.info("Request: {} {} - Status: {} - Time: {}ms", exchange.getRequest().getMethod(), exchange.getRequest().getURI().getPath(), exchange.getResponse().getStatusCode(), duration); })); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } }
步骤7:限流配置
// RateLimiterConfig.java package com.example.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; @Configuration public class RateLimiterConfig { @Bean public KeyResolver userKeyResolver() { return exchange -> { // 根据用户限流 String userId = exchange.getRequest() .getHeaders() .getFirst("X-User-Id"); if (userId != null) { return Mono.just(userId); } // 根据IP限流 String ip = exchange.getRequest() .getRemoteAddress() .getAddress() .getHostAddress(); return Mono.just(ip); }; } @Bean public KeyResolver apiKeyResolver() { return exchange -> Mono.just( exchange.getRequest().getURI().getPath() ); } }
步骤8:熔断降级处理
// FallbackController.java package com.example.gateway.controller; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @RestController public class FallbackController { @GetMapping("/fallback/user") public Mono<ResponseEntity<Map<String, Object>>> userServiceFallback() { return Mono.just(ResponseEntity .status(HttpStatus.SERVICE_UNAVAILABLE) .body(createFallbackResponse("User service is temporarily unavailable"))); } @GetMapping("/fallback/product") public Mono<ResponseEntity<Map<String, Object>>> productServiceFallback() { return Mono.just(ResponseEntity .status(HttpStatus.SERVICE_UNAVAILABLE) .body(createFallbackResponse("Product service is temporarily unavailable"))); } private Map<String, Object> createFallbackResponse(String message) { Map<String, Object> response = new HashMap<>(); response.put("success", false); response.put("message", message); response.put("timestamp", System.currentTimeMillis()); response.put("code", 503); return response; } }
步骤9:安全配置
// SecurityConfig.java package com.example.gateway.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; @Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .csrf().disable() .authorizeExchange() .pathMatchers("/actuator/**", "/fallback/**").permitAll() .pathMatchers("/api/auth/**").permitAll() .pathMatchers("/api/public/**").permitAll() .anyExchange().authenticated() .and() .httpBasic().disable() .formLogin().disable() .build(); } }
步骤10:健康检查配置
// HealthCheckConfig.java package com.example.gateway.config; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; @Component public class HealthCheckConfig implements ReactiveHealthIndicator { @Override public Mono<Health> health() { return checkDownstreamServiceHealth() .onErrorResume(ex -> Mono.just( Health.down().withException(ex).build()) ); } private Mono<Health> checkDownstreamServiceHealth() { // 检查下游服务健康状态 return Mono.just(Health.up().build()); } }
步骤11:动态路由配置(基于数据库)
// DynamicRouteService.java package com.example.gateway.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; import java.util.List; @Service public class DynamicRouteService { @Autowired private RouteDefinitionWriter routeDefinitionWriter; @Autowired private ApplicationEventPublisher publisher; @PostConstruct public void initRoutes() { // 从数据库加载路由配置 loadRoutesFromDatabase(); } private void loadRoutesFromDatabase() { // 实现从数据库加载路由的逻辑 } public void addRoute(RouteDefinition definition) { routeDefinitionWriter.save(Mono.just(definition)).subscribe(); refreshRoutes(); } public void updateRoute(RouteDefinition definition) { deleteRoute(definition.getId()); addRoute(definition); } public void deleteRoute(String routeId) { routeDefinitionWriter.delete(Mono.just(routeId)).subscribe(); refreshRoutes(); } private void refreshRoutes() { publisher.publishEvent(new RefreshRoutesEvent(this)); } }
三、测试验证
创建测试配置
# application-test.yml spring: cloud: gateway: routes: - id: test-route uri: http://httpbin.org:80 predicates: - Path=/get/** filters: - AddRequestHeader=Hello, World logging: level: org.springframework.cloud.gateway: DEBUG com.example.gateway: DEBUG
编写测试用例
// GatewayTest.java package com.example.gateway; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; import org.springframework.test.web.reactive.server.WebTestClient; import static com.github.tomakehurst.wiremock.client.WireMock.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureWireMock(port = 8081) class GatewayTest { @Autowired private WebTestClient webClient; @Test void testRoute() { stubFor(get(urlEqualTo("/test")) .willReturn(aResponse() .withBody("test") .withHeader("Content-Type", "text/plain"))); webClient.get() .uri("/test") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("test"); } }
四、部署配置
Docker部署配置
# Dockerfile FROM openjdk:11-jre-slim VOLUME /tmp COPY target/api-gateway-*.jar app.jar ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"] EXPOSE 8080
Kubernetes配置
# deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: api-gateway spec: replicas: 3 selector: matchLabels: app: api-gateway template: metadata: labels: app: api-gateway spec: containers: - name: api-gateway image: api-gateway:latest ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: "prod" resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m" livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 60 periodSeconds: 30 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 15
五、总结
优势特点:
- 性能优秀:基于WebFlux响应式编程,非阻塞IO,高并发能力强
- 功能全面:内置路由、过滤、熔断、限流等核心功能
- 易于扩展:支持自定义过滤器和全局过滤器
- 云原生友好:完美整合Spring Cloud生态
- 配置灵活:支持YAML配置、Java配置和动态配置
最佳实践:
- 路由设计:合理规划API路径,遵循RESTful规范
- 安全防护:统一认证授权,实施请求验证
- 性能监控:集成监控系统,实时收集指标
- 容错处理:配置熔断降级,确保系统可用性
- 版本管理:支持API版本控制,平滑升级
注意事项:
- 网关应保持轻量级,避免复杂业务逻辑
- 合理配置超时时间和重试机制
- 实施灰度发布和蓝绿部署
- 定期更新和维护路由规则
- 监控网关性能,及时扩容
通过Spring Cloud Gateway,我们可以构建一个高性能、可扩展、安全的API网关,有效管理和保护微服务架构中的API接口,提升系统的整体稳定性和可维护性。
谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海