微服务之网关路由

一、概述

1.1认识网关

什么是网关?

顾明思议,网关就是络的口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验

更通俗的来讲,网关就像是以前园区传达室的大爷。

  • 外面的人要想进入园区,必须经过大爷的认可,如果你是不怀好意的人,肯定被直接拦截。

  • 外面的人要传话或送信,要找大爷。大爷帮你带给目标人。

现在,微服务网关就起到同样的作用。前端请求不能直接访问微服务,而是要请求网关:

  • 网关可以做安全控制,也就是登录身份校验,校验通过才放行

  • 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去

 1.2SpringCloudGateway概述

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring6,Spring Boot 3和Project Reactor等技术。它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式,并为它们提供跨领域的关注点,例如:安全性、监控/度量和恢复能力。

在SpringCloud当中,提供了两种网关实现方案:

  • Netflix Zuul:早期实现,目前已经淘汰

  • SpringCloudGateway:基于Spring的WebFlux技术,完全支持响应式编程,吞吐能力更强

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控 

1.3Gateway核心介绍

Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息,从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册进服务注册中心。

Route(路由)

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过虑器组成,如果断言为true则匹配该路由

Predicate(断言)

参考的是Java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

Filter(过滤)

指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

  • 在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等;
  • 在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

总结

web前端请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。

predicate就是我们的匹配条件;

filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了

二、快速入门

接下来,我们先看下如何利用网关实现请求路由。由于网关本身也是一个独立的微服务,因此也需要创建一个模块开发功能。大概步骤如下:

  • 创建网关微服务

  • 引入SpringCloudGateway、NacosDiscovery依赖

  • 编写启动类

  • 配置网关路由

.创建项目

pom依赖

<dependencies><!--gateway--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--服务注册发现consul discovery,网关也要注册进服务注册中心统一管控--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies>

yml配置

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: http://localhost:8001                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: http://localhost:8001                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

启动类

@SpringBootApplication
@EnableDiscoveryClient //服务注册和发现
public class Main9527
{public static void main(String[] args){SpringApplication.run(Main9527.class,args);}
}

测试

@RestController
public class PayGateWayController
{@ResourcePayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public ResultData<Pay> getById(@PathVariable("id") Integer id){Pay pay = payService.getById(id);return ResultData.success(pay);}@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo(){return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());}
}

配置

相同公司

@FeignClient(value = "cloud-payment-service")//自己人内部,自己访问自己,写微服务名字OK
public interface PayFeignApi
{/*** GateWay进行网关测试案例01* @param id* @return*/@GetMapping(value = "/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id);/*** GateWay进行网关测试案例02* @return*/@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo();
}

不同公司

存在ym配置,映射写死问题

三、GateWay高级特性

3.1Route以微服务名-动态获取服务URI

 gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service          #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

3.2Predicate断言(谓词)

整体架构

两种配置方式

 Shortcut Configuration

 After Route Predicate

获取datatime

public class ZonedDateTimeDemo
{public static void main(String[] args){ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区System.out.println(zbj);}
}

yml配置

  predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- After=2024-4-16T14:37:50.586918800+08:00[Asia/Shanghai]

Before Route Predicate

  predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-11-27T15:25:06.424566300+08:00[Asia/Shanghai] #超过规定时间不可访问

Between Route Predicate

predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]#- Before=2023-11-20T17:58:13.586918800+08:00[Asia/Shanghai]- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]

Cookie Route Predicate

Cookie Route Predicate需要两个参数,一个是 Cookie name ,一个是正则表达式。

路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行
  predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]- Cookie=username,zzyy

Header Route Predicate

两个参数:一个是属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。

predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]#- Cookie=username,zzyy- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

Host Route Predicate

Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则。

  predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]#- Cookie=username,zzyy#- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式- Host=**.atguigu.com

Path Route Predicate

  predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]#- Cookie=username,zzyy#- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式- Host=**.atguigu.com

Query Route Predicate

支持传入两个参数,一个是属性名,一个为属性值,属性值可以是正则表达式。

predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]#- Cookie=username,zzyy#- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式#- Host=**.atguigu.com- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由

RemoteAddr route predicate

   predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]#- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]#- Cookie=username,zzyy#- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式#- Host=**.atguigu.com#- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由- RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。

Method Route Predicate

配置某个清求地址,只能用Get/Post方法访问,方法限制

总结

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai]#- Cookie=username,zzyy# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式#- Host=**.atguigu.com#- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由#- RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

3.3自定义断言

开头任意取名,但是必须以RoutePredicateFactory后缀结尾


1.新建类名XXX需要以RoutePredicateFactory结尾并继承AbstractRoutePredicateFactory类

@Component标注不可忘public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{}

2.重写appy方法

@Override
public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
{return null;
}

3.新建apply方法所需要的静态内部类MyRoutePredicateFactory.Config这个Config类就是我们的路由断言规侧,重要

@Validated
public static class Config{@Setter@Getter@NotEmptyprivate String userType; //钻、金、银等用户等级
}

4.空参构造方法,内部调用super

public MyRoutePredicateFactory()
{super(MyRoutePredicateFactory.Config.class);
}

5.重写apply方法第二版

@Override
public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
{return new Predicate<ServerWebExchange>(){@Overridepublic boolean test(ServerWebExchange serverWebExchange){//检查request的参数里面,userType是否为指定的值,符合配置就通过String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");if (userType == null) return false;//如果说参数存在,就和config的数据进行比较if(userType.equals(config.getUserType())) {return true;}return false;}};
}

 完整

// 使用@Component注解,将该类声明为一个Spring组件
@Component
// 继承AbstractRoutePredicateFactory类,并指定泛型参数为Config类
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {// 构造函数,调用父类的构造函数,传入Config类的类型public MyRoutePredicateFactory() {super(MyRoutePredicateFactory.Config.class);}// 定义一个静态内部类Config,用于存储配置信息@Validatedpublic static class Config {@Setter@Getter@NotEmptyprivate String userType; // 用户等级,如钻、金、银等}// 重写apply方法,接收一个Config类型的参数,返回一个Predicate<ServerWebExchange>对象@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {// 返回一个新的Predicate<ServerWebExchange>对象return new Predicate<ServerWebExchange>() {// 重写test方法,接收一个ServerWebExchange类型的参数@Overridepublic boolean test(ServerWebExchange serverWebExchange) {// 从请求中获取userType参数的值String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");// 如果userType为空,则返回falseif (userType == null) return false;// 如果userType与config中的userType相等,则返回trueif (userType.equals(config.getUserType())) {return true;}// 其他情况返回falsereturn false;}};}
}

yml配置

          predicates:- Path=/pay/gateway/get/**  # 断言,路径相匹配的进行路由- After=2024-04-16T14:43:38.193234700+08:00[Asia/Shanghai]
#            - My=diamond- name: Myargs:userType: diamond

短处配置

@Override
public List<String> shortcutFieldOrder() {return Collections.singletonList("userType");
}

3.4Filteri过滤

pre"和“post”分别会在请求被执行前调用和被执行后调用用来修改请求和响应信息

功能:

  • 请求鉴权
  • 异常处理
  • 记录接口调用时长统计,重点,大厂面试设计题

 全局默认过滤器Global Filters

  • gateway出厂默认已有的,直接用即可,主要作用于所有的路由
  • 不需要在配置文件中配置,作用在所有的路由上,实现GlobalFilter接口即可

单一内置讨虑器GatewavFilter

也可以称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由分组

自定义过滤器

3.5请求头(RequestHeader)相关组

The AddRequestHeader GatewayFilter Factory】

指定请求头

测试类

 @GetMapping(value = "/pay/gateway/filter")public ResultData<String> getGatewayFilter(HttpServletRequest request){String result = "";Enumeration<String> headers = request.getHeaderNames();while(headers.hasMoreElements()){String headName = headers.nextElement();String headValue = request.getHeader(headName);System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);if(headName.equalsIgnoreCase("X-Request-atguigu1")|| headName.equalsIgnoreCase("X-Request-atguigu2")) {result = result+headName + "\t " + headValue +" ";}}return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}

yml配置

- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2

The RemoveRequestHeader GatewayFilter Factory yml配置

删除请求头ByName

          filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site

The SetRequestHeader GatewayFilter Factory

修改请求头ByName

          filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy

3.6请求参数(RequestParameter)相关组

  • The AddRequestParameter GatewayFilter Factory
  • The RemoveRequestParameter GatewayFilter Factory

3.7回应头(ResponseHeader)相关组

            - AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

3.8前缀和路径相关组(重要)

The PrefixPath GatewayFilter Factory

  • 自动添加路径前缀
  predicates:#- Path=/pay/gateway/filter/**   # 被分拆为: PrefixPath + Path- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/payfilters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  #请求头kv,若一头含有多参则重写一行设置#- AddRequestHeader=X-Request-atguigu2,atguiguValue2#- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site#- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy#- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v#- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null#- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除- PrefixPath=/pay # http://localhost:9527/pay/gateway/filter

The SetPath GatewayFilter Factory

  • 访问路径修改
  predicates:#- Path=/pay/gateway/filter/** # 真实地址#- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  #请求头kv,若一头含有多参则重写一行设置#- AddRequestHeader=X-Request-atguigu2,atguiguValue2#- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site#- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy#- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v#- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null#- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除#- PrefixPath=/pay # http://localhost:9527/pay/gateway/filter- SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致

The RedirectTo GatewayFilter Factory

  • 重定向到某个页面
     
  predicates:- Path=/pay/gateway/filter/** # 真实地址#- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay#- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  #请求头kv,若一头含有多参则重写一行设置#- AddRequestHeader=X-Request-atguigu2,atguiguValue2#- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site#- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy#- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v#- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null#- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除#- PrefixPath=/pay # http://localhost:9527/pay/gateway/filter- RedirectTo=302, http://www.atguigu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/

3.9Default Filters

配置在比处相当于全局通用,自定义秒变Global
 

3.10自定义全局Filter

@Component //不要忘记
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){return null;}@Overridepublic int getOrder(){return 0;}
}

yml配置

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{/*** 数字越小优先级越高* @return*/@Overridepublic int getOrder(){return 0;}private static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始访问时间/***第2版,各种统计* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//先记录下访问接口的开始时间exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());return chain.filter(exchange).then(Mono.fromRunnable(()->{Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);if (beginVisitTime != null){log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");log.info("我是美丽分割线: ###################################################");System.out.println();}}));}}

3.11自定义条件Filter

省略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/624706.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024中国内燃机展-北京汽车发动机零部件展

2024第二十三届中国国际内燃机与零部件展览会 由中国内燃机工业协会主办、中国机床专用技术设备有限公司、汽车工艺装备成套开发集团协办的2024中国国际内燃机及动力装备博览会&#xff08;简称“动博会”&#xff09;将于2024年10月11日-13日在亦创国际会展中心隆重举办。本届…

OpenHarmony开发案例:【分布式遥控器】

1.概述 目前家庭电视机主要通过其自带的遥控器进行操控&#xff0c;实现的功能较为单一。例如&#xff0c;当我们要在TV端搜索节目时&#xff0c;电视机在遥控器的操控下往往只能完成一些字母或数字的输入&#xff0c;而无法输入其他复杂的内容。分布式遥控器将手机的输入能力…

Backend - Django Swagger

目录 一、安装依赖 二、配置环境 三、路由&#xff08;urls&#xff09; 四、swagger UI 界面 &#xff08;一&#xff09;UI 界面 &#xff08;二&#xff09;单引号问题&#xff1a;Expecting property name enclosed in double quotes 1. 原因 2. 解决 五、自定义s…

Day 27 39. 组合总和 40.组合总和II 131.分割回文串

组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&#xff08;包括 target&#xff09;都是正整数。解集不能…

CentOS下gitlab迁移和升级_gitlab备份的可以通用centos和 ubuntu吗(1)

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

IAM 统一身份认证与访问管理服务

即统一身份认证与访问管理服务&#xff0c;是云服务商提供的一套云上身份管理解决方案&#xff0c;可帮助企业安全地管理云上资源的访问权限。 在当今云计算时代&#xff0c;企业越来越依赖云服务来存储和处理敏感数据。然而&#xff0c;这也带来了新的安全挑战&#xff0c;即…

牛客2024 【牛客赛文X】春招冲刺 ONT84 子数组的最小值之和【中等 单调栈 Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/a7401d0dd4ec4071a31fd434e150bcc2 思路 单调栈解决的问题单调栈解决的问题是在一个数组中想知道所有数中&#xff0c; 左边离他近的比他大的和右边离他近的比他大的数 思考的问题&#xff1a;如果知道所有数上…

Web前端开发——Ajax,Axios概述及在Vue框架中的使用

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup!!! Ajax Ajax是什么&#xff1f; Ajax全称Asynchromous JavaScript And Xml&#xff0c;是异步的JavaScript和Xml。 Ajax的作用&#xff1f; 1&#xff0c;数据交换&#xff1a;通过Ajax可以给服务器…

使用undetected-chromedriver遇到的问题及解决方法,以及它使用SOCKS代理的问题

环境&#xff1a;python3.8.10 uc的安装方法&#xff1a; pip38 install undetected-chromedriver 上测试代码&#xff1a; import undetected_chromedriver as uc driver uc.Chrome() driver.get(https://www.baidu.com) driver.save_screenshot(baidu.png)报错&#xff…

Java项目如何使用EasyExcel插件对Excel数据进行导入导出

文章目录 一、EasyExcel的示例导入依赖创建实体类数据导入和导出 二、EasyExcel的作用三、EasyExcel的注解 EasyExcel是一个阿里巴巴开源的excel处理框架&#xff0c;它以使用简单、节省内存著称。在解析Excel时&#xff0c;EasyExcel没有将文件数据一次性全部加载到内存中&…

权限管理Ranger详解

文章目录 一、Ranger概述与安装1、Ranger概述1.1 Ranger介绍1.2 Ranger的目标1.3 Ranger支持的框架1.4 Ranger的架构1.5 Ranger的工作原理 2、Ranger安装2.1 创建系统用户和Kerberos主体2.2 数据库环境准备2.3 安装RangerAdmin2.4 启动RangerAdmin 二、Ranger简单使用1、安装 R…

python之flask安装以及使用

1 flask介绍 Flask是一个非常小的Python Web框架&#xff0c;被称为微型框架&#xff1b;只提供了一个稳健的核心&#xff0c;其他功能全部是通过扩展实现的&#xff1b;意思就是我们可以根据项目的需要量身定制&#xff0c;也意味着我们需要学习各种扩展库的使用。 2 python…