云计算百科
云计算领域专业知识百科平台

Spring Cloud Gateway基础

Spring Cloud Gateway 网关

1. 网关概述

1.1 什么是网关

在这里插入图片描述

API网关为微服务架构的系统提供简单、有效且统一的API路由管理,作为系统的统一入口,提供内部服务的路由中转,给客户端提供统一的服务。网关可以实现与业务解耦的公共逻辑,主要功能包括:

  • 认证鉴权:验证用户身份和权限
  • 路由转发:将请求路由到相应的微服务
  • 安全策略:实施安全防护措施
  • 流量控制:限流、熔断、降级
  • 监控日志:请求监控和日志记录
  • 防刷防护:防止恶意请求

1.2 主流网关技术选型

  • Kong:基于Nginx和Lua开发的网关
  • Zuul:Netflix第一代网关,需要二次开发实现高级功能
  • Nginx + Lua:自定义网关方案
  • Spring Cloud Gateway:Spring官方第二代网关(推荐)
  • 自研网关:根据业务需求定制开发
  • 2. Spring Cloud Gateway 简介

    2.1 概述

    Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,旨在取代Netflix Zuul。它基于WebFlux + Netty + Reactor实现,采用响应式编程模型,不能在传统的Servlet容器中工作,也不能构建成WAR包。

    官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

    2.2 核心特性

    • 基于Spring Framework 5,Project Reactor和Spring Boot 2.x
    • 动态路由
    • 断言和过滤器
    • 集成Hystrix断路器
    • 集成Spring Cloud DiscoveryClient
    • 易于编写的断言和过滤器
    • 请求限流
    • 路径重写

    3. 核心概念

    3.1 路由(Route)

    路由是网关的基本构建块,包含:

    • ID:唯一标识符
    • 目标URI:路由到的目标地址
    • 断言集合:匹配请求的条件
    • 过滤器集合:请求处理链

    3.2 断言(Predicate)

    断言是Java 8函数式断言,用于匹配HTTP请求中的任何内容(如请求头、参数等)。当断言匹配成功时,请求才会被路由到相应的目标地址。

    3.3 过滤器(Filter)

    Spring Cloud Gateway过滤器用于修改请求和响应:

    • Gateway Filter:特定路由的过滤器
    • Global Filter:全局应用的过滤器
    • Pre Filter:代理请求前执行的逻辑
    • Post Filter:代理请求后执行的逻辑

    4. 工作原理

    4.1 请求处理流程

    在这里插入图片描述

    • 客户端向SpringCloud Gateway发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关Web处理程序,此时处理程序运行特定的请求过滤器链。
    • 过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行post过滤器逻辑。

    在这里插入图片描述

  • 请求到达DispatcherHandler
  • DispatcherHandler根据请求分发到对应RoutePredicateHandlerMapping
  • 将请求转给FilteringWebHandler
  • FilteringWebHandler会拿到很多filter去执行
  • 最后通过nety将请求发到服务端
  • 5. 快速开始

    5.1 项目配置

    pom.xml依赖

    <dependencies>
    <!– 公共模块 –>
    <dependency>
    <groupId>com.example</groupId>
    <artifactId>mall-common</artifactId>
    <version>1.0</version>
    </dependency>

    <!– Lombok –>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>

    <!– Gateway网关 –>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!– Nacos服务发现 –>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    </dependencies>

    application.yml配置

    spring:
    application:
    name: mallgateway

    # Nacos配置
    cloud:
    nacos:
    discovery:
    server-addr: 127.0.0.1:8848

    # Gateway配置
    gateway:
    routes:
    # 订单服务路由
    id: order_route
    uri: lb://mallorder
    predicates:
    Path=/order/**

    # 用户服务路由
    id: user_route
    uri: lb://malluser
    predicates:
    Path=/api/user/**
    filters:
    StripPrefix=1 # 去除一层路径

    # WebFlux应用类型
    main:
    web-application-type: reactive

    5.2 启动类

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

    6. 路由器断言工厂配置

    predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地。application.yml配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件

    官方文档:https://docs.spring.jo/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

    6.1 路径匹配

    predicates:
    Path=/order/**
    Path=/api/user/**

    6.2 Header匹配

    predicates:
    Path=/api/user/**
    Header=XRequestId, \\d+ # 请求头X-Request-Id值为数字

    6.3 其他常用断言

    • Method:请求方法匹配
    • Query:请求参数匹配
    • Cookie:Cookie匹配
    • Host:主机名匹配
    • Before/After/Between:时间窗口匹配

    7. 过滤器工厂配置

    GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理

    官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

    在这里插入图片描述

    7.1 添加请求头

    filters:
    AddRequestHeader=XRequestColor, red

    微服务端获取请求头

    @GetMapping("/test")
    public String testGateway(@RequestHeader("X-Request-Color") String color) {
    log.info("获取请求头颜色: {}", color);
    return "success";
    }

    7.2 添加请求参数

    filters:
    AddRequestParameter=color, blue

    7.3 自定义过滤器工厂

    @Component
    @Slf4j
    public class CheckAuthGatewayFilterFactory
    extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
    return (exchange, chain) -> {
    log.info("调用CheckAuthGatewayFilterFactory: {} = {}",
    config.getName(), config.getValue());
    return chain.filter(exchange);
    };
    }
    }

    配置使用

    filters:
    CheckAuth=zs,# 自定义过滤器工厂,名称必须符合规范

    8. 全局过滤器配置

    8.1 自定义全局过滤器

    @Component
    @Slf4j
    public class CheckAuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 1. 获取Token
    String token = exchange.getRequest().getHeaders().getFirst("token");

    if (StringUtils.isEmpty(token)) {
    log.warn("Token为空,拒绝访问");
    return unauthorizedResponse(exchange);
    }

    // 2. 验证Token(实际项目中需要调用认证服务)
    if (!validateToken(token)) {
    return unauthorizedResponse(exchange);
    }

    // 3. Token验证通过,添加用户信息到请求头
    UserInfo userInfo = parseToken(token);
    ServerHttpRequest request = exchange.getRequest().mutate()
    .header("username", userInfo.getUsername())
    .header("userId", userInfo.getUserId())
    .build();

    return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
    return 0;
    }

    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange) {
    ServerHttpResponse response = exchange.getResponse();
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

    String message = "{\\"code\\": 401, \\"message\\": \\"未授权访问\\"}";
    DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());

    return response.writeWith(Mono.just(buffer));
    }
    }

    9. 跨域配置

    9.1 YAML配置方式

    官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration

    spring:
    cloud:
    gateway:
    globalcors:
    cors-configurations:
    '[/**]':
    allowed-origins: "*"
    allowed-methods:
    GET
    POST
    PUT
    DELETE
    OPTIONS
    allowed-headers: "*"
    allow-credentials: true
    max-age: 3600

    9.2 Java配置方式

    @Configuration
    public class CorsConfig {

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

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

    return new CorsWebFilter(source);
    }
    }

    10. 限流配置

    10.1 常见限流算法

    令牌桶算法

    在这里插入图片描述

    • 令牌以固定速率生成并存入桶中
    • 请求需要消耗令牌才能被处理
    • 桶满时多余令牌被丢弃
    • 令牌不足时请求被缓存或拒绝
    漏桶算法

    在这里插入图片描述

    • 请求以任意速率进入漏桶
    • 漏桶以固定速率处理请求
    • 桶满时新请求被丢弃
    滑动窗口算法

    在这里插入图片描述

    • 将时间划分为多个窗口
    • 统计窗口内的请求数量
    • 超过阈值则拒绝请求

    10.2 Gateway基于Redis + Lua限流实现

    springcloud alibaba官方提供了RequestRateLimiter过滤器工厂,基于redis+lua脚本方式采用令牌桶算法实现了限流。

    官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-requestratelimiter-gatewayfilter-factory

    在这里插入图片描述

    添加依赖

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

    配置限流

    spring:
    redis:
    host: 192.168.10.60
    port: 6379
    database: 0
    lettuce:
    pool:
    max-active: 200
    max-idle: 100
    min-idle: 10

    cloud:
    gateway:
    routes:
    id: user_route
    uri: lb://malluser
    predicates:
    Path=/api/user/**
    filters:
    name: RequestRateLimiter
    args:
    redis-rate-limiter.replenishRate: 1 # 每秒令牌生成数
    redis-rate-limiter.burstCapacity: 2 # 令牌桶容量
    key-resolver: "#{@pathKeyResolver}" # 限流Key解析器

    配置Key解析器

    @Configuration
    public class RateLimiterConfig {

    /**
    * 按路径限流
    */

    @Bean
    public KeyResolver pathKeyResolver() {
    return exchange ->
    Mono.just(exchange.getRequest().getURI().getPath());
    }

    /**
    * 按参数限流
    */

    @Bean
    public KeyResolver parameterKeyResolver() {
    return exchange ->
    Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }

    /**
    * 按IP限流
    */

    @Bean
    public KeyResolver ipKeyResolver() {
    return exchange ->
    Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    }

    测试:

    在这里插入图片描述

    11. 微服务鉴权集成

    11.1 鉴权流程

    客户端请求 → 网关 → 认证中心验证Token → 返回用户信息
    → 网关添加用户信息到请求头 → 转发到微服务 → 微服务从请求头获取用户信息

    在这里插入图片描述

    11.2 网关配置

    免认证URL配置

    mall:
    gateway:
    should-skip-urls:
    /oauth/**
    /sso/**
    /home/**
    /pms/**

    配置类

    @Data
    @ConfigurationProperties(prefix = "mall.gateway")
    public class NotAuthUrlProperties {
    private Set<String> shouldSkipUrls = new LinkedHashSet<>();
    }

    认证过滤器

    @Component
    @Slf4j
    @EnableConfigurationProperties(NotAuthUrlProperties.class)
    public class AuthorizationFilter implements GlobalFilter, Ordered {

    @Autowired
    private NotAuthUrlProperties notAuthUrlProperties;

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

    // 1. 检查是否为免认证路径
    if (shouldSkip(currentUrl)) {
    log.info("跳过认证路径: {}", currentUrl);
    return chain.filter(exchange);
    }

    log.info("需要认证路径: {}", currentUrl);

    // 2. 获取并验证Token
    String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

    if (StringUtils.isEmpty(authHeader)) {
    log.warn("认证路径缺少Token");
    return unauthorizedResponse(exchange);
    }

    // 3. 验证Token(实际调用认证服务)
    UserInfo userInfo = validateToken(authHeader);
    if (userInfo == null) {
    return unauthorizedResponse(exchange);
    }

    // 4. 添加用户信息到请求头
    ServerHttpRequest request = exchange.getRequest().mutate()
    .header("username", userInfo.getUsername())
    .header("userId", userInfo.getUserId())
    .build();

    return chain.filter(exchange.mutate().request(request).build());
    }

    private boolean shouldSkip(String currentUrl) {
    PathMatcher pathMatcher = new AntPathMatcher();
    return notAuthUrlProperties.getShouldSkipUrls().stream()
    .anyMatch(pattern -> pathMatcher.match(pattern, currentUrl));
    }

    @Override
    public int getOrder() {
    return 1;
    }
    }

    11.3 微服务端配置

    用户信息DTO

    @Data
    public class UserInfoDto {
    private String username;
    private String userId;
    private String role;
    private String department;
    }

    ThreadLocal工具类

    public class UserInfoHolder {

    private static final ThreadLocal<UserInfoDto> USER_INFO = new ThreadLocal<>();

    public static void setUserInfo(UserInfoDto userInfo) {
    USER_INFO.set(userInfo);
    }

    public static UserInfoDto getUserInfo() {
    return USER_INFO.get();
    }

    public static void clear() {
    USER_INFO.remove();
    }
    }

    拦截器

    @Component
    @Slf4j
    public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response,
    Object handler) {
    // 从请求头获取用户信息
    String userId = request.getHeader("userId");
    String username = request.getHeader("username");

    if (StringUtils.isNotBlank(userId)) {
    UserInfoDto userInfo = new UserInfoDto();
    userInfo.setUserId(userId);
    userInfo.setUsername(username);
    UserInfoHolder.setUserInfo(userInfo);
    }

    return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
    HttpServletResponse response,
    Object handler,
    Exception ex) {
    UserInfoHolder.clear();
    }
    }

    拦截器注册

    @Configuration
    public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(authInterceptor)
    .addPathPatterns("/**")
    .excludePathPatterns("/health", "/actuator/**");
    }
    }

    12. 最佳实践

    12.1 生产环境建议

  • 高可用部署:网关集群部署,配合负载均衡
  • 监控告警:集成Prometheus + Grafana监控
  • 日志收集:统一日志格式,使用ELK收集
  • 配置中心:动态路由配置,避免重启
  • 熔断降级:集成Resilience4j或Sentinel
  • 12.2 性能优化

  • 连接池优化:调整Netty和Redis连接池参数
  • 缓存策略:合理使用本地缓存和Redis缓存
  • 异步处理:充分利用响应式编程优势
  • 限流策略:多层次限流保护
  • 12.3 安全建议

  • HTTPS:生产环境强制使用HTTPS
  • WAF集成:配合Web应用防火墙
  • 审计日志:记录关键操作日志
  • 定期更新:及时更新依赖库版本
  • 13. 常见问题排查

    13.1 启动问题

    • 问题:启动失败,提示Servlet相关错误
    • 解决:检查spring.main.web-application-type=reactive

    13.2 路由失效

    • 问题:配置的路由不生效
    • 解决:检查路由ID唯一性,断言配置正确性

    13.3 跨域问题

    • 问题:浏览器提示跨域错误
    • 解决:检查CORS配置,确保OPTIONS请求正确处理

    13.4 限流异常

    • 问题:限流配置不生效
    • 解决:检查Redis连接,确认KeyResolver配置正确

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Spring Cloud Gateway基础
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!