微服务之网关路由

一、概述

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.mzph.cn/news/822089.shtml

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

相关文章

跨境物流系统解决方案:构建全球化供应链的关键步骤

随着全球化的发展&#xff0c;跨境物流已成为国际贸易中不可或缺的重要环节。然而&#xff0c;由于各国之间的政治、法律、文化和语言差异&#xff0c;跨境物流常常面临诸多挑战&#xff0c;如货物清关、运输安全、物流跟踪等问题。因此&#xff0c;构建一个高效、可靠的跨境物…

3.2 iHRM人力资源 - 组织架构 - 编辑及删除

iHRM人力资源 - 组织架构 文章目录 iHRM人力资源 - 组织架构一、编辑功能1.1 表单弹层并数据回显1.2 编辑校验1.3 编辑 二、删除功能 一、编辑功能 编辑功能和新增功能用的组件其实是一个&#xff0c;结构几乎是一样的&#xff0c;其实是复用了组件&#xff0c;我们也省去了很…

Hive-Sql复杂面试题

参考链接&#xff1a;hive sql面试题及答案 - 知乎 1、编写sql实现每个用户截止到每月为止的最大单月访问次数和累计到该月的总访问次数 数据&#xff1a; userid,month,visits A,2015-01,5 A,2015-01,15 B,2015-01,5 A,2015-01,8 B,2015-01,25 A,2015-01,5 A,2015-02,4 A,20…

用于密集视觉冲击的紧凑三维高斯散射Compact 3D Gaussian Splatting For Dense Visual SLAM

Compact 3D Gaussian Splatting For Dense Visual SLAM 用于密集视觉冲击的紧凑三维高斯散射 Tianchen Deng 邓天辰11Yaohui Chen 陈耀辉11Leyan Zhang 张乐妍11Jianfei Yang 杨健飞22Shenghai Yuan 圣海元22Danwei Wang 王丹伟22Weidong Chen 陈卫东11 Abstract 摘要 …

淘宝API商品详情数据在数据分析行业中具有不可忽视的重要性

淘宝商品详情数据在数据分析行业中具有不可忽视的重要性。这些数据为商家、市场分析师以及数据科学家提供了丰富的信息&#xff0c;有助于他们更深入地理解市场动态、消费者行为以及商品竞争态势。以下是淘宝商品详情数据在数据分析行业中的重要性体现&#xff1a; 请求示例&a…

ArcGIS三维景观分层显示

今天将向大家介绍的事在ArcGIS中如何创建多层三维显示。 地表为影像的 地表为地形晕渲的 在土壤分层、油气分层等都有着十分重要的应用。下面我们具体来看看实现过程 一、 准备数据及提取栅格范围 我们这次准备的数据是之前GIS100例-30讲的案例数据。《ArcGIS三维影像图剖面图…

基于栈求解迷宫的单条路径和所有路径

数据结构与算法课的一个实验&#xff0c;记录一下。 单纯想要了解利用栈求解迷宫的算法可以直接跳转到相应的小标题。 完整代码链接code_2024/mazeLab LeePlace_OUC/code - 码云 - 开源中国 (gitee.com) 文章目录 要求栈的实现MazeType类型的组织迷宫的初始化和销毁打印路径…

AIGC实战——VQ-GAN(Vector Quantized Generative Adversarial Network)

AIGC实战——VQ-GAN 0. 前言1. VQ-GAN2. ViT VQ-GAN小结系列链接 0. 前言 本节中&#xff0c;我们将介绍 VQ-GAN (Vector Quantized Generative Adversarial Network) 和 ViT VQ-GAN&#xff0c;它们融合了变分自编码器 (Variational Autoencoder, VAE)、Transformer 和生成对…

Vue加载glb / gltf模型(如何在vue中使用Three.js,vue使用threejs加载glb模型)

简介&#xff1a;Three.js 是一个用于在 Web 上创建和显示 3D 图形的 JavaScript 库。它提供了丰富的功能和灵活的 API&#xff0c;使开发者可以轻松地在网页中创建各种 3D 场景、模型和动画效果。可以用来展示产品模型、建立交互式场景、游戏开发、数据可视化、教育和培训等等…

嵌入式4-16

tftpd #include <myhead.h> #define SER_IP "192.168.125.243" //服务器IP地址 #define SER_PORT 69 //服务器端口号 #define CLI_IP "192.168.125.244" //客户端IP地址 #define CLI_PORT 8889 //客户端端…

解读科技智慧公厕改变生活的革命性创新之路

公共厕所&#xff0c;作为城市基础设施的一部分&#xff0c;一直以来都备受人们诟病。脏乱差、设施老旧、管理混乱&#xff0c;成为公共厕所长期存在的问题。然而&#xff0c;随着科技的不断进步&#xff0c;智慧公厕应运而生&#xff0c;为解决公厕难题&#xff0c;智慧公厕源…

【ElasticSearch】安装(bug篇)

以下解决办法参考自网友们的分享 1. JDK绑定问题 但其实这样也没有问题&#xff0c;因为内嵌的jdk版本与当前的es版本是适配的 但是&#xff0c;如果内嵌的jdk与当前es不适配&#xff0c;那就要修改配置文件 / 添加环境变量&#xff0c;让es启动的时候能扫描到我们本地的jdk …

校园水电能源智能化管理系统

校园作为大量人员集聚的场所&#xff0c;水电能源的高效管理对于降低运营成本、保障安全稳定供应以及推动可持续发展至关重要。校园水电能源智能化管理系统应运而生&#xff0c;通过先进技术的应用&#xff0c;实现了对校园水电资源的智能监控、计量和管理。本文将从系统背景、…

Elasticsearch:下载、启动和账号密码登录

因为我的电脑是 window&#xff0c;以下都是以 window 环境举例。 一、下载 Elasticsearch 是使用 java 开发的&#xff0c;且 7.8 版本的 ES 需要 JDK 版本 1.8 以上&#xff0c;安装前注意java环境的准备。 官网地址&#xff1a;https://www.elastic.co/cn/ 下载地址&#xf…

最新可用免费云服务器推荐汇总

随着云计算技术的不断发展&#xff0c;越来越多的企业和个人开始关注并尝试使用云服务器。云服务器以其高度的灵活性、可扩展性和成本效益&#xff0c;成为了部署应用和存储数据的理想选择。本文将为大家汇总目前市场上最新可用的免费云服务器资源&#xff0c;帮助大家更好地了…

Linux基础|线程池Part.1|线程池的定义和运行逻辑

线程池的定义和运行逻辑 多线程的问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低系统的效率&#xff0c;因为频繁创建线程和销毁线程需要时间。 那么一个很自然的想法就出现了…

AI音乐,8大变现方式——Suno:音乐版的ChatGPT - 第505篇

悟纤之歌 这是利用AI为自己制作的一首歌&#xff0c;如果你也感兴趣&#xff0c;可以花点时间阅读下本篇文章。 ​ 导读 随着新一代AI音乐创作工具Suno V3、Stable audio2.0、天工SkyMusic的发布&#xff0c;大家玩自创音乐歌曲&#xff0c;玩的不亦乐乎。而有创业头脑的朋友…

mysql 转pg 两者不同的地方

因项目数据库&#xff08;原来是MySQL&#xff09;要改成PostgreSQL。 项目里面的sql要做一些调整。 1&#xff0c;写法上的区别&#xff1a; 1&#xff0c;数据准备&#xff1a; 新建表格&#xff1a; CREATE TABLE property_config ( CODE VARCHAR(50) NULL…

【UE5.1】使用MySQL and MariaDB Integration插件——(4)修改、插入、删除数据

目录 效果 步骤 一、修改 二、插入、删除 在上一篇博客&#xff08;【UE5.1】使用MySQL and MariaDB Integration插件——&#xff08;3&#xff09;表格形式显示数据&#xff09;基础上继续实现修改、插入和删除数据库数据的功能 效果 修改数据&#xff1a; 插入数据&…

java线程(1)

1、多线程启动 有两种启动方式 1、实现Runable接口 2、继承Thread类并且重写run&#xff08;&#xff09;方法 在执行进程中的任务才会产生线程&#xff0c;所以需要实现Runable接口并且重写run&#xff08;&#xff09;方法&#xff0c;然后将Runable的实现对象作为参数传…