Spring Cloud Alibaba GateWay的网关过滤工厂

网关过滤器工厂(Gateway Filter Factory)允许以某种方式修改传入的HTTP请求或返回的HTTP响应。其作用域是某些特定路由。

一、AddRequestHeader过滤工厂

该过滤器工厂会对匹配上的请求添加指定的请求头Header。

1.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          predicates:
            - Path=/**
          filters:
            - AddRequestHeader=X-Request-Color, blue
            - AddRequestHeader=X-Request-Color, red
            - AddRequestHeader=X-Request-Color, yellow
            - AddRequestHeader=X-Request-Color, green

1.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * AddRequestHeader网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterAddRequestHeaderRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterAddRequestHeader_route", predicateSpec -> predicateSpec.path("/**")
                        .filters(filterSpec -> filterSpec.addRequestHeader("X-Request-Color", "pink")
                                .addRequestHeader("X-Request-Color", "black")
                                .addRequestHeader("X-Request-Color", "white"))
                        .uri("http://localhost:8080"))
                .build();
    }
}

1.3 测试

@RestController
@RequestMapping("/info")
public class ShowInfoController {

    @GetMapping("/header")
    public String headerHandle(HttpServletRequest request) {
        Enumeration<String> headers = request.getHeaders("X-Request-Color");
        StringBuilder stringBuilder = new StringBuilder();
        // 如果headers含有元素,则取出所有值
        while (headers.hasMoreElements()) {
            stringBuilder.append(headers.nextElement() + " ");
        }
        return "X-Request-Color: " + stringBuilder.toString();
    }
}

二、AddRequestHeadersIfNotPresent过滤工厂

该过滤器工厂会对匹配上的请求添加指定的 header,前提是该 header 在当前请求中尚未出现过。请求中允许出现多个同名的请求头。即同一名称的请求头可以被多次添加到请求中。但有些场景下为了保证请求中对于某请求头只有一个值,就可以使用该过滤工厂。

2.1 配置式路由方式

如果配置了多个AddRequestHeadersIfNotPresent属性,那么只生效第一个,其余的不会生效

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          #uri: https://baidu.com
          predicates:
            - Path=/**
          filters:
            - AddRequestHeadersIfNotPresent=X-Request-Color:blue, city:beijing # 只有第一个会生效
            - AddRequestHeadersIfNotPresent=X-Request-Color:red, city:changchun # 不会生效

2.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * AddRequestHeadersIfNotPresent网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterAddRequestHeadersIfNotPresentRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterAddRequestHeadersIfNotPresent_route", predicateSpec -> predicateSpec.path("/**")
                        .filters(filterSpec -> filterSpec.addRequestHeadersIfNotPresent("X-Request-Color:black", "city:siping") // 只有这个会生效
                                .addRequestHeadersIfNotPresent("X-Request-Color:white", "city:lishu") // 不会生效,因为已经存在了
                                .addRequestHeadersIfNotPresent("X-Request-Color:green", "city:jilin")) // 不会生效
                        .uri("http://localhost:8080"))
                .build();
    }
}

三、AddRequestParameter过滤工厂

该过滤器工厂会对匹配上的请求添加指定的请求参数。

3.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          #uri: https://baidu.com
          predicates:
            - Path=/**
          filters:
            - AddRequestParameter=color, blue
            - AddRequestParameter=color, red
            - AddRequestParameter=color, green
            - AddRequestParameter=city, bj
            - AddRequestParameter=fruit, apple
            - AddRequestParameter=size, 123

3.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * AddRequestParameter网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterAddRequestParameterRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterAddRequestParameter_route", predicateSpec -> predicateSpec.path("/**")
                        .filters(filterSpec -> filterSpec.addRequestParameter("color", "blue")
                                                        .addRequestParameter("color", "red")
                                                        .addRequestParameter("fruit", "beijing")
                                                        .addRequestParameter("city", "jilin"))
                        .uri("http://localhost:8080"))
                .build();
    }
}

四、AddResponseHeader过滤工厂

该过滤器工厂会给从网关返回的响应添加上指定的请求头Header。

4.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          #uri: https://baidu.com
          predicates:
            - Path=/**
          filters:
            - AddResponseHeader=X-Response-Color, Blue
            - AddResponseHeader=X-Response-Color, Red

4.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * AddResponseHeader网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterAddResponseHeaderRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterAddResponseHeader_route", predicateSpec -> predicateSpec.path("/**")
                        .filters(filterSpec -> filterSpec.addResponseHeader("color", "blue")
                                .addResponseHeader("color", "red")
                                .addResponseHeader("fruit", "beijing")
                                .addResponseHeader("city", "jilin"))
                        .uri("http://localhost:8080"))
                .build();
    }
}

五、CircuitBreaker过滤工厂

该过滤器工厂完成网关层的服务熔断与降级。当访问的处理器不成功时,将服务降级到Gateway工程中定义的降级处理器上。

5.1 添加上resilience4j依赖

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

5.2 定义降级处理器

@RestController
public class FallbackController {
    @RequestMapping("/fb")
    public String fallbackHander() {
        return "服务熔断后降级到了这个处理器!";
    }
}

5.3 配置过滤器

5.3.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          #uri: https://baidu.com
          predicates:
            - Path=/**
          filters:
            - name: CircuitBreaker # filter工厂名称
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/fb # 如果发生了服务熔断之后要进行服务降级,这是设置降级位置
  • name属性:用于指定要使用的过滤器Filter类型,不能随意写。

  • args属性:指定过滤器Filter的配置参数。

    • args属性的name属性:用于指定当前所使用断路器的名称,可以随意。

    • args属性的fallbackUri属性:用于指定发生断路后要提交的降级URI。

5.3.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * CircuitBreaker网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterCircuitBreakerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterCircuitBreaker_route", predicateSpec -> predicateSpec.path("/**")
                        .filters(filterSpec -> filterSpec.circuitBreaker(config -> {
                            config.setName("myCircuitBreaker");
                            config.setFallbackUri("forward:/fb");
                        }))
                        .uri("http://localhost:8080"))
                .build();
    }
}

六、PrefixPath过滤工厂

该过滤器工厂会自动的为指定的URI前面添加上一个指定的URI前辍。

6.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8081
          predicates:
            - Path=/depart/**
          filters:
            - PrefixPath=/provider

6.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * PrefixPath网关过滤工厂 —— API式
     *
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterPrefixPathRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterPrefixPath_route", predicateSpec -> predicateSpec.path("/depart/**")
                        .filters(filterSpec -> filterSpec.prefixPath("/provider"))
                        .uri("http://localhost:8081"))
                .build();
    }
}

七、StripPrefix过滤工厂

该过滤器工厂会为指定的URI去掉指定长度的前辍。

7.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8081
          predicates:
            #- Path=/provider/depart/**
            #- Path=/first/second/provider/depart/**
            - Path=/*/*/provider/depart/**
          filters:
            - StripPrefix=2 # 指定去掉2个前辍

7.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * StripPrefix网关过滤工厂 —— API式
     * 
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterStripPrefixRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                //.route("filterStripPrefix_route", predicateSpec -> predicateSpec.path("/first/second/provider/depart/**")
                .route("filterStripPrefix_route", predicateSpec -> predicateSpec.path("/*/*/provider/depart/**")
                        .filters(filterSpec -> filterSpec.stripPrefix(2))
                        .uri("http://localhost:8081"))
                .build();
    }
}

八、RewritePath过滤工厂

该过滤器工厂会将请求URI替换为另一个指定的URI进行访问。

RewritePath有两个参数,第一个是正则表达式,第二个是要替换为的目标表达式。

8.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8081
          predicates:
            #- Path=/red/blue/balck/**
            - Path=/red/**
          filters:
            #- RewritePath=/red/blue/balck, /provider/depart
            - RewritePath=/red/?(?<segment>.*), /$\{segment}
            # localhost:9000/red/provider/depart/list ————> localhost:9000/provider/depart/list
            # localhost:9000/red/wang/quan/97/list ————> localhost:9000/wang/quan/97/list

8.2 API式路由方式

@Configuration
public class GatewayConfig {

    /**
     * RewritePath网关过滤工厂 —— API式
     * 
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator filterRewritePathRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("filterRewritePat_route", predicateSpec -> predicateSpec.path("/red/**")
                        .filters(filterSpec -> filterSpec.rewritePath("/red/?(?<segment>.*)", "/$\\{segment}"))
                        .uri("http://localhost:8081"))
                .build();
    }
}

九、RequestRateLimiterGateway过滤工厂

该过滤器工厂通过令牌桶算法对进来的请求进行限流。

9.1 添加Redis依赖

这个限流器是基于Redis的,所以需要导入Redis的Starter依赖。

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

9.2 添加限流键解析器

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

    /**
     * 限流key为用户
     * 根据请求要访问的目标服务器的用户进行限流
     */
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }

    /**
     * 限流key为目标服务器的host/ip
     * 根据请求要访问的目标服务器的host或ip进行限流
     */
    @Bean
    KeyResolver hostKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }

    /**
     * 限流key为URI
     * 根据请求要访问的目标服务器的URI进行限流
     */
    @Bean
    KeyResolver pathKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
}

9.3 配置式路由方式

spring:
  data:
    redis:
      host: 192.168.11.137
      port: 6379
      database: 1
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8081
          predicates:
            - Path=/provider/depart/**
          filters:
            - name: RequestRateLimiter
              args:
                key-resolver: "#{@hostKeyResolver}"
                redis-rate-limiter.replenishRate: 2 # 令牌桶算法中令牌每秒的填充速率
                redis-rate-limiter.burstCapacity: 5 # 突发容量,请求突然增大时生成令牌的速率可以在原来基础上+5
                redis-rate-limiter.requestedTokens: 1 # 每处理一个请求需要的令牌数量

十、默认Filters工厂

前面的网关过滤工厂是在某一特定路由策略中设置的,仅对这一种路由生效。若要使某些过滤效果应用到所有路由策略中,就可以将该网关过滤工厂定义在默认Filters中。

10.1 修改配置文件

default-filters下定义的路由为默认路由,而routers的filters下定义的路由则为局部路由。

spring:
  data:
    redis:
      host: 192.168.11.137
      port: 6379
      database: 1
  cloud:
    gateway:
      default-filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/fb
      routes:
        - id: my_route1
          uri: http://localhost:8080
          predicates:
            - Path=/bd/**
        - id: my_route2
          uri: http://localhost:8081
          predicates:
            - Path=/blbl/**

10.2 过滤工厂的优先级

对于相同的过滤工厂,在不同位置设置了不同的值,则优先级为:

  • 局部过滤工厂的优先级高于默认过滤工厂
  • API式的过滤工厂优先级高于配置式过滤工厂

十一、自定义网关过滤工厂

定义一个类, 该类类名由两部分构成:后面必须是GatewayFilterFactory,前面为功能前缀,该前缀将来要用在配置文件中。

@Component
public class AddHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return ((exchange, chain) -> {
            ServerHttpRequest changedRequest = exchange.getRequest()
                                                        .mutate() // 变更
                                                        .header(config.getName(), config.getValue())
                                                        .build();

            ServerWebExchange changedExchange = exchange.mutate()
                                                        .request(changedRequest)
                                                        .build();

            return chain.filter(changedExchange);
        });
    }
}

11.1 配置式路由方式

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          predicates:
            - Path=/info/**
          filters:
            - AddHeader=new-color, red

十二、GatewayFilter的pre与post

Gateway有“pre”和“post”两种方式的Filter。客户端的请求先按照Filter的优先级顺序(优先级相同,则按注册顺序),执行Filter的“pre”部分。然后将请求转发到相应的目标服务器,收到目标服务器的响应之后,再按照Filter的优先级顺序的逆序(优先级相同,则按注册顺序逆序),执行Filter的“post”部分,最后返回响应到客户端。

Filter的“pre”部分指的是chain.filter()方法执行之前的代码,而“post”部分,则是定义在chain.filter().then()方法中的代码。

12.1 定义过滤器

@Slf4j
@Component
public class OneGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return ((exchange, chain) -> {
            // pre-filter
            long start = System.currentTimeMillis();
            log.info(config.getName() + "——" + config.getValue() + "-pre,开始执行的时间:" + start);
            exchange.getAttributes().put("startTime", start);
            return chain.filter(exchange).then(
                    // post-filter
                    Mono.fromRunnable(() -> {
                        long startTime = (long) exchange.getAttributes().get("startTime");
                        long endTime = System.currentTimeMillis();
                        long elapsedTime = endTime - startTime;
                        log.info(config.getName() + "——" + config.getValue() + "-post,执行完毕的时间:" + endTime);
                        log.info("这个过滤器执行用时(毫秒):" + elapsedTime);
                    })
            );
        });
    }
}
@Slf4j
@Component
public class TwoGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return ((exchange, chain) -> {
            // pre-filter
            log.info(config.getName() + "——" + config.getValue() + "-pre");

            return chain.filter(exchange).then(
                    // post-filter
                    Mono.fromRunnable(() -> {
                        log.info(config.getName() + "——" + config.getValue() + "-post");
                    })
            );
        });
    }
}
@Slf4j
@Component
public class ThreeGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return ((exchange, chain) -> {
            // pre-filter
            log.info(config.getName() + "——" + config.getValue() + "-pre");

            return chain.filter(exchange).then(
                    // post-filter
                    Mono.fromRunnable(() -> {
                        log.info(config.getName() + "——" + config.getValue() + "-post");
                    })
            );
        });
    }
}

 12.2 修改配置文件

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://localhost:8080
          predicates:
            - Path=/info/**
          filters: # 过滤器按顺序执行
            - One=onefilter, 111
            - Three=threefilter, 333
            - Two=twofilter, 222

12.3 测试

@RestController
@RequestMapping("/info")
public class ShowInfoController {

    @GetMapping("/time")
    public String timeHandle() {
        return "到达目标服务器的时间:" + System.currentTimeMillis();
    }
}

十三、全局过滤器

全局过滤器Global Filter是应用于所有路由策略上的Filter。Gateway中已经定义好了很多GlobalFilter,但这些GlobalFilter无需任何的配置与声明,在符合应用条件时就会自动生效。

Global Filter不需要在任何具体的路由规则中进行注册,只需在类上添加@Compoment 注解,将其生命周期交给Spring容器来管理即可。

例:访问当前系统的任意模块的URL都需要是合法的URL,即请求中携带了token请求参数。

因为对所有请求的URL都要进行验证,所以这里就需要定义一个Global Filter,可以应用到所有路由中。

13.1 定义全局过滤器

@Component
public class UrlValidateGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 从请求中获取请求参数token的值
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        // 如果token为空,则响应客户端状态码401,未授权。否则通过验证
        if (!StringUtils.hasText(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        // 为当前GlobalFilter赋予最高的优先级
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

在浏览器进行访问自己项目中的任意处理器方法。如果请求中没有携带token请求参数,则验证失败。请求中携带了token参数,无论其值为什么均可通过验证。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring CloudSpring Cloud Alibaba都是基于Spring Framework的开源框架,用于构建分布式系统和微服务架构。它们都提供了一系列的组件和工具来简化微服务开发和管理。 Spring Cloud是一个由Pivotal团队维护的项目,它集成了Netflix开源的一些组件,如Eureka作为注册中心、Ribbon作为负载均衡器、Feign作为服务调用工具等。同时,Spring Cloud还提供了其他功能,如Config Server用于动态管理配置、Gateway用于构建API等。 而Spring Cloud Alibaba则是阿里巴巴开源的项目,它在Spring Cloud的基础上进行了扩展和定制,增加了一些阿里巴巴自己的组件和工具。比如,它使用Nacos作为注册中心和配置中心,使用Sentinel作为熔断降级工具。 总的来说,Spring CloudSpring Cloud Alibaba都是用于构建微服务架构的框架,它们的区别在于Spring Cloud集成了Netflix组件,而Spring Cloud Alibaba集成了阿里巴巴的一些组件。根据具体的需求和技术栈选择使用哪个框架可以更好地满足开发和管理微服务的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring Cloud AlibabaSpring Cloud的区别](https://blog.csdn.net/weixin_43888891/article/details/126653270)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值