0


Gateway自定义过滤器——全局过滤器

一、什么是全局过滤器🍉

首先,我们要知道全局过滤器其实是特殊路由过滤器(特殊的GatewayFilter),会有条件地作用于所有路由。
为什么要自定义全局过滤器?就好比是看大门的保安大叔,平时主要是做好进出大门外来人员登记即可,但是因为新冠疫情,现在还需要给外来人员测量体温等等。而已有的全局过滤器就好比是登记操作,而自定义的全局过滤器就好比是测量体温操作,是结合具体场景添加的。

比如以下场景:

  • 认证判断
  • 权限校验
  • 黑白名单
  • 跨域配置

工作原理:

当请求与路由匹配时,过滤WebHandler会将GlobalFilter的所有实例和GatewayFilter的所有特定于路由的实例添加到过滤器链中。该组合的过滤器链由org.springframework.core.Ordered接口排序,您可以通过实现getOrder()方法进行设置。
由于Spring Cloud Gateway区分了过滤器逻辑执行的“前”阶段和“后”阶段,因此具有最高优先级的过滤器在“前”阶段中是第一个,在“后”阶段中是最后一个。

二、自带的全局过滤器包含哪些🍉

要自定义全局过滤,首先我们应该去了解一下gateway自带的主要的全局过滤器有哪些,并了解他们的作用。

  • ForwardRoutingFilter

ForwardRoutingFilter在exchange属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。如果URL具有转发scheme(例如forward:/// localendpoint),则它将使用Spring DispatcherHandler来处理请求。请求URL的路径部分被转发URL中的路径覆盖。未经修改的原始URL会附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。

  • LoadBalancerClientFilter

LoadBalancerClientFilter在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的exchange属性中查找URI。如果URL的方案为lb(例如lb:// myservice),它将使用Spring Cloud LoadBalancerClient将名称(在本例中为myservice)解析为实际的主机和端口,并替换同一属性中的URI。未经修改的原始URL会附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。过滤器还会在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性中查找其是否等于lb。如果是,则适用相同的规则。下面的清单配置一个LoadBalancerClientFilter:

spring:
  cloud:
    gateway:
      routes:- id: myRoute
        uri: lb://service
        predicates:-Path=/service/**

注意1:默认情况下,当在LoadBalancer中找不到服务实例时,将返回503。您可以通过设置spring.cloud.gateway.loadbalancer.use404 = true将网关配置为返回404。

注意2:从LoadBalancer返回的ServiceInstance的isSecure值将覆盖对网关的请求中指定的方案。例如,如果请求通过HTTPS进入网关,但是ServiceInstance指示它不安全,则下游请求通过HTTP发出。相反的情况也可以适用。但是,如果在网关配置中为路由指定了GATEWAY_SCHEME_PREFIX_ATTR,则会删除前缀,并且路由URL产生的方案将覆盖ServiceInstance配置。

注意3:LoadBalancerClientFilter在默认情况下使用阻塞的LoadBalancerClient。建议改用ReactiveLoadBalancerClientFilter。可以通过将spring.cloud.loadbalancer.ribbon.enabled的值设置为false来切换到该值。

  • ReactiveLoadBalancerClientFilter

ReactiveLoadBalancerClientFilter与上面的LoadBalancerClientFilter类似,差异主要是ReactiveLoadBalancerClientFilter是非阻塞的。

注意1:与LoadBalancerClientFilter一样,默认情况下,当ReactorLoadBalancer无法找到服务实例时,将返回503。您可以通过设置spring.cloud.gateway.loadbalancer.use404 = true将网关配置为返回404。

  • NettyRoutingFilter

如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的exchange属性中的URL带有http或https,则将运行NettyRoutingFilter。它使用Netty HttpClient发出下游代理请求。响应将放入ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR的exchange属性中,供后面的过滤器使用。 (还有一个实验性的WebClientHttpRoutingFilter,它执行相同的功能,但不需要Netty。)

经过该过滤器时,会通过ServerWebExchangeUtils.setAlreadyRouted方法把exchange对象标记为“已路由”。

  • RouteToRequestUrlFilter

如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR的exchange属性中存在Route对象,则RouteToRequestUrlFilter将运行。它基于请求URI创建一个新URI,但使用Route对象的URI属性进行更新。新的URI放置在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的exchange属性中。

如果URI具有scheme前缀(例如lb:ws://serviceid),则将从URI中剥离lb方案,并将其放在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中,以供后面在过滤器链中使用。

  • WebsocketRoutingFilter

顾名思义,WebsocketRoutingFilter过滤器是用于处理websocket请求的,如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的exchange属性中的URL具有ws或wss的schema,则将运行WebsocketRoutingFilter。它使用Spring WebSocket基础结构向下游转发websocket请求。

您可以通过为URI加上lb前缀来平衡websocket的负载,例如lb:ws://serviceid

经过该过滤器时,会通过ServerWebExchangeUtils.setAlreadyRouted方法把exchange对象标记为“已路由”。

配置示例如下,通常情况下,除了配置ws,还需要配置一个http的,因为发起websocket连接的请求是http请求。

# 官方示例
spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:-Path=/websocket/info/**
      # Normal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**
  • GatewayMetricsFilter

该过滤器主要用于做网关度量监控的,要启用,需添加spring-boot-starter-actuator依赖。然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled未设置为false,GatewayMetricsFilter就会运行。此过滤器添加一个带有以下标记的计时器度量标准,名为gateway.requests:

  • routeId: 路由ID.
  • routeUri: 需要路由的API
  • outcome: 结果分类参考 HttpStatus.Series.
  • status: 返回给客户端的http status
  • httpStatusCode: 返回给客户端的http status
  • httpMethod: 用户请求的http Method 这些指标随后可从/actuator/metrics/gateway.requests中进行抓取,并可轻松地与Prometheus集成以创建Grafana dashboard。

要启用prometheus端点,请添加micrometer-registry-prometheus依赖。

三、如何自定义全局过滤器🍉

在这里演示过滤黑白名单

1.在配置文件中定义黑白名单🥝

在这里插入图片描述

#配置端口号
server:
  port:81
#服务名称
spring:
  application:
    name: qy165-lzq
#配置路径规则
  cloud:
    gateway:
      routes:- id: lzq01 #路由的唯一标识-------随便起只要不重复就可以  如果不写默认uuid创建
          uri: http://localhost:8001  # 真是转发地址
          predicates:                 # 断言  当满足当前条件时进行跳转到uri  可以理解为判断
            -Path=/aaa/**

        - id: lzq02
          uri: lb://lzq-01      #lb 表示跳转方式 获取nacos上的服务器名
          predicates:
            - Path=/aaa/**
#连接nacos地址
    nacos:
      discovery:
        server-addr: localhost:8848
        register-enabled: false

filter:
  whitePaths:
    - "/product/login"
    - "/product/aaa"
    - "/product/bbb"
  blackPaths:
    - "/product/ccc"

2.定义工具类读取黑白名单🥝

在这里插入图片描述

packagecom.lzq.filter;importlombok.Data;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;importjava.util.HashSet;importjava.util.Set;@Component@ConfigurationProperties(prefix ="filter")@DatapublicclassFilterUrl{privateSet<String> whitePaths=newHashSet<>();privateSet<String> blackPaths=newHashSet<>();}

3.编写过滤器🥝

定义实体类实现接口

在这里插入图片描述

packagecom.lzq.filter;importcom.alibaba.fastjson.JSON;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.cloud.gateway.filter.GatewayFilterChain;importorg.springframework.cloud.gateway.filter.GlobalFilter;importorg.springframework.core.Ordered;importorg.springframework.core.io.buffer.DataBuffer;importorg.springframework.http.server.reactive.ServerHttpRequest;importorg.springframework.http.server.reactive.ServerHttpResponse;importorg.springframework.stereotype.Component;importorg.springframework.util.StringUtils;importorg.springframework.web.server.ServerWebExchange;importreactor.core.publisher.Mono;importjava.nio.charset.StandardCharsets;importjava.util.HashMap;importjava.util.Map;@ComponentpublicclassLogFilterimplementsGlobalFilter,Ordered{@AutowiredprivateFilterUrl filterUrl;@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//过滤的业务代码//1.获取请求路径---String path = request.getPath().toString();//判断该路径是否放行路径if(filterUrl.getWhitePaths().contains(path)){return chain.filter(exchange);}//获取请求头String token = request.getHeaders().getFirst("token");if(StringUtils.hasText(token)&&"admin".equals(token)){//查看redis中是否存在该tokenreturn chain.filter(exchange);//放行}//json数据Map<String,Object> map =newHashMap<>();
        map.put("msg","未登录");
        map.put("code",403);//3.3作JSON转换byte[] bytes =JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8);//3.4调用bufferFactory方法,生成DataBuffer对象DataBuffer buffer = response.bufferFactory().wrap(bytes);//4.调用Mono中的just方法,返回要写给前端的JSON数据return response.writeWith(Mono.just(buffer));}//Ordered:优先级 值越小 优先级越高@OverridepublicintgetOrder(){return0;}}

4.解决跨域问题🥝

第一种方式创建实体类

在这里插入图片描述

packagecom.lzq.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.reactive.CorsWebFilter;importorg.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;importorg.springframework.web.util.pattern.PathPatternParser;importjava.util.Date;@ConfigurationpublicclassCorConfig{//处理跨域@BeanpublicCorsWebFiltercorsFilter(){CorsConfiguration config =newCorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source =newUrlBasedCorsConfigurationSource(newPathPatternParser());
        source.registerCorsConfiguration("/**", config);returnnewCorsWebFilter(source);}}

第二种方式在配置文件中编写

在这里插入图片描述

server:
  port:81
spring:
  application:
    name: gateway  #服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos地址
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping:true
        cors-configurations:'[/**]':  #拦截的请求
            allowedOrigins: #允许跨域的请求
              -"http://localhost:8080"
            allowedMethods: #运行跨域的请求方式
              -"GET"-"POST"-"DELETE"-"PUT"-"OPTIONS"
            allowedHeaders:"*" #允许请求中携带的头信息
            allowedCredentials:true #是否允许携带cookie
            maxAge:36000 #跨域检测的有效期,单位s
标签: gateway java 前端

本文转载自: https://blog.csdn.net/2301_77444674/article/details/131772976
版权归原作者 低调的黑客 所有, 如有侵权,请联系我们删除。

“Gateway自定义过滤器——全局过滤器”的评论:

还没有评论