9.Gateway新一代网关

article/2025/8/17 11:24:14

目录

一、Gateway概述

二、Gateway三大核心

三、Gateway工作流程

入门配置

建Module

改POM

写YML

主启动

业务类

测试

四、9527网关进行路由映射

1.编写支付正常业务逻辑

2.9527网关YML新增配置

3.测试1

4.测试2

启动订单微服务测试,看看是否通过网关?

1.修改cloud-api-commons

2.修改cloud-consumer-feign-order88

正确做法

同一家公司自己人,系统内环境,直接找微服务

不同家公司有外人,系统外访问,先找网关再服务

​编辑

1.刷新feign接口jar包

2.重启80订单微服务

3.有网关正常success

4.无网关异常

五、GateWay高级特性

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

ReactiveLoadBalancerClientFilter(负载均衡和动态路由)

uri地址修改为动态获取

测试1:

测试2:

Predicate断言(谓词)

简介

内置断言工厂介绍

常见的内置Route Predicate使用

Shortcut Configuration 快捷方式

Fully Expanded Arguments 完全展开

1.After Route Predicate (后路由谓词工厂)

2. Before Route Predicate(前路由谓词工厂)

3. Between Route Predicate(中间路由谓词工厂)

4. Cookie Route Predicate (Cookie路线谓词工厂)

​编辑

5. Header Route Predicate(头文件路由谓词工厂)

6. Host Route Predicate (主机路由谓词工厂)

7.Method Route Predicate(方法路由谓语工厂)

8. Path Route Predicate (路径路由谓词工厂)

9. Query Route Predicate(查询路由谓词工厂)

10.RemoteAddr route predicate(远程地址路由谓词工厂)

上述配置小总结

自定义断言,XXXRoutePredicateFactory规则

自定义RoutePredicateFactory实现方式

自定义路由断言规则步骤套路

编写步骤

完整代码

测试1

bug分析

测试2

完整代码02

Filter过滤

概述

作用:

类型:

Gateway内置的过滤器

1.请求头(RequestHeader)相关组

6.1.The AddRequestHeader GatewayFilter Factory(添加请求头网关过滤器工厂)

6.18.The RemoveRequestHeader GatewayFilter Factory(移除请求头网关过滤器工厂)

6.29.The SetRequestHeader GatewayFilter Factory(设置请求头网关过滤器工厂)

2.请求参数(RequestParameter)相关组

6.3 The AddRequestParameter GatewayFilter Factory(添加请求参数网关过滤器工厂)

6.19 The RemoveRequestParamter GatewayFilter Factory(移除请求参数网关过滤器工厂)

请求参数示例(6.3/6.19):

3.回应头(ResponseHeader)相关组

6.4 The AddResponseHeader GatewayFilter Factory(新增响应头网关过滤器工厂)

6.30 The SetResponseHeader GatewayFilter Factory(设置/修改响应头网关过滤器工厂)

6.20 The RemoveResponseHeader GatewayFilter Factory(移除响应头网关过滤器工厂)

请求参数示例(6.4/6.30/6.20):

4.前缀和路径相关组

6.14.The PrefixPath GatewayFilter Factory(前缀路径网关过滤器工厂)

6.29.The SetPath GatewayFilter Factory(设置路径网关过滤器工厂)

6.16.The RedirectTo GatewayFilter Factory(重定向到网关过滤器工厂)

5. 其它

6.38. Default Filters(默认全局过滤器)

本次案例全部YML配置全集

Gateway自定义过滤器

自定义全局Filter

面试题

官方介绍

示例

自定义条件Filter

自定义网关过滤器规则步骤套路

YML 参数配置

测试

相关知识拓展:


概述
Gateway三大核心
Gateway工作流程
入门配置
9527网关如何做路由映射
GateWay高级特性
Gateway整合阿里巴巴Sentinel实现容错

一、Gateway概述

官网地址: https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html
gitHub地址: GitHub - spring-cloud/spring-cloud-gateway: An API Gateway built on Spring Framework and Spring Boot providing routing and more.
Gateway简介
Gateway是在Spring生态系统之上构建的 API网关服务 ,基于Spring6,Spring Boot 3和Project Reactor等技术。它旨在 为微服务架构提供一种简单有效的统一的 API 路由管理方式 ,并为它们提供跨领域的关注点,例如:安全性、监控/度量和恢复能力。
Gateway在springCloud中的体系定位
Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul,那就是SpringCloud Gateway一句话:gateway是原zuul1.x版的替代 
微服务架构中网关位置
Gateway功能:
  • 反向代理
  • 鉴权流量
  • 控制熔断
  • 日志监控
使用场景/功能详解:
Spring Cloud Gateway是一个基于Spring Framework的反向代理和路由器,它可以用于构建微服务架构中的 API 网关。除了反向代理之外,Spring Cloud Gateway还提供了许多功能,包括鉴权、限流、熔断和日志监控等。
1.反向代理
Spring Cloud Gateway可以作为应用程序的前端,将所有的请求转发到后端的服务实例上。
它支持HTTP和WebSocket协议,并且具有高性能和低延迟的特点。
通过负载均衡算法,可以在多个后端服务实例之间进行请求的分发。
2.鉴权
Spring Cloud Gateway提供了灵活的鉴权机制,可以根据请求的路径、方法、头部信息等来进行鉴权控制。
可以与Spring Security等安全框架集成,实现基于角色或权限的访问控制。
也可以使用自定义过滤器来实现特定的鉴权逻辑,例如基于令牌、API密钥等的验证。
3.限流
Spring Cloud Gateway支持基于请求速率、并发数、IP地址等进行请求的限流控制。
可以使用内置的限流过滤器或者自定义过滤器来实现限流策略。
通过限流可以保护后端的服务免受恶意攻击和过载请求的影响。
4.熔断
Spring Cloud Gateway可以使用熔断器来处理后端服务的故障或异常情况。
当后端服务出现错误时,可以通过配置熔断策略,在一定时间内禁止对该服务的请求,从而防止故障蔓延和影响其他服务。
5.日志监控:
Spring Cloud Gateway提供了丰富的日志功能,可以记录请求和响应的详细信息,帮助开发人员进行故障排查和性能优化。
可以将日志输出到控制台、文件或者集成ELK等日志分析工具进行进一步的处理。
也可以使用监控工具对网关的性能和流量进行实时监控和统计。
总之,Spring Cloud Gateway在构建微服务架构中起到了重要的作用,不仅可以作为反向代理来转发请求,还提供了丰富的功能来增强系统的安全性、稳定性和可观察性。以上介绍的鉴权、限流、熔断和日志监控是其中的核心功能之一,可以根据具体的需求和场景进行灵活配置和扩展。
Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息,从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册进服务注册中心。

二、Gateway三大核心

  • Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
  • Predicate(断言):参考的是Java8的iava.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
  • Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
web前端请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。
predicate就是我们的匹配条件;
filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了

三、Gateway工作流程

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(Pre)或之后(Post)执行业务逻辑。
  • 在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等;
  • 在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
核心逻辑:路由转发+断言判断+执行过滤器链

入门配置

  • 建Module
  • 改POM
  • 写YML
  • 主启动
  • 自业务类
  • 测试
建Module
cloud-gateway9527
改POM
<!--gateway 依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
模块所有pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>mscloudV5</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-gateway9527</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><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><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
写YML
server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}
主启动
package com.atguigu.cloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient //服务注册和发现
public class Main9527
{public static void main(String[] args){SpringApplication.run(Main9527.class,args);}
}
业务类
无,不写任何业务代码,网关和业务无关
测试
备注:
  • 先启动8500服务中心Consul
  • 再启动9527网关入驻

四、9527网关进行路由映射

我们目前不想暴露8001端口希望在8001真正的支付微服务外面套一层9527网关
将编写的正常业务逻辑,添加gateway进行路由映射

1.编写支付正常业务逻辑

8001新建 PayGateWayController
package com.atguigu.cloud.controller;import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.service.PayService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@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());}
} 
启动8001支付
8001自测,查看业务代码是否正常
  • http://localhost:8001/pay/gateway/get/1
  • http://localhost:8001/pay/gateway/info

2.9527网关YML新增配置

cloud-gateway9527 模块添加网关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/**              # 断言,路径相匹配的进行路由

3.测试1

启动Consul8500服务
启动8001支付
启动9527网关
访问说明
目前8001支付微服务前面添加GateWay成功
启动Consul8500服务
启动8001支付
启动9527网关
访问说明:
1.添加网关前的地址
  • http://localhost:8001/pay/gateway/get/1
  • http://localhost:8001/pay/gateway/info
2.添加网关后的地址
  • http://localhost:9527/pay/gateway/get/1
  • http://localhost:9527/pay/gateway/info
3.隐真显假,映射说明
目前8001支付微服务前面添加GateWay成功
GateWay9527 → Pay8001

4.测试2

启动订单微服务测试,看看是否通过网关?
我们启动80订单微服务,它从Consul注册中心通过微服务名称找到8001支付微服务进行调用,80 → 9527 → 8001
要求访问9527网关后才能访问8001,如果我们此时启动80订单,可以做到吗?
1.修改cloud-api-commons
PayFeignApi接口
package com.atguigu.cloud.apis;import com.atguigu.cloud.entities.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;@FeignClient(value = "cloud-payment-service")
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();}
2.修改cloud-consumer-feign-order88
新建0rderGateWaycontroller
package com.atguigu.cloud.controller;import com.atguigu.cloud.apis.PayFeignApi;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OrderGateWayController
{@Resourceprivate PayFeignApi payFeignApi;@GetMapping(value = "/feign/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id){return payFeignApi.getById(id);}@GetMapping(value = "/feign/pay/gateway/info")public ResultData<String> getGatewayInfo(){return payFeignApi.getGatewayInfo();}
}
3.网关开启
测试通过
  • http://localhost/feign/pay/gateway/get/1
  • http://localhost/feign/pay/gateway/info
4.网关关闭
测试通过
  • http://localhost/feign/pay/gateway/get/1
  • http://localhost/feign/pay/gateway/info
5.结论 
9527网关是否启动,毫无影响,0(-…T)0
目前的配置来看,网关被绕开了
正确做法
同一家公司自己人,系统内环境,直接找微服务
@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();
}
不同家公司有外人,系统外访问,先找网关再服务
//@FeignClient(value = "cloud-payment-service")//自己人内部,自己访问自己,写微服务名字OK
@FeignClient(value = "cloud-gateway")//不同家公司有外人,系统外访问,先找网关再服务
public interface PayFeignApi
备注:需要与GateWay模块,注册的服务名相同
1.刷新feign接口jar包
2.重启80订单微服务
3.有网关正常success
4.无网关异常
但是application.yml还存在写死的情况,需要在高级特性中进行配置

五、GateWay高级特性

  • Route以微服务名-动态获取服务URI
  • Predicate浙言(谓词)
  • Filter过滤

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

ReactiveLoadBalancerClientFilter(负载均衡和动态路由)
ReactiveLoadBalancerClientFilter是Spring Cloud Gateway中的一个核心组件,主要用于在微服务架构中实现负载均衡和动态路由。
ReactiveLoadBalancerClientFilter 在名为 ServerWebExchangeUtilS.GATEWAY_REQUEST URL ATTR 的交换属性中查找 UR!。如果 URL 具有lb方案(例如 1b:/myservice),则Spring Cloud ReactorLoadBalancer将将名称(在此示例中为 myservice)解析为实际的主机和端口号,并替换同一属性中的 URI。未修改的原始 URL 附加到ServerWebExchangeUtilS.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性的列表中。该过滤器还检查ServerWebExchangeUtils的 GATEWAY_SCHEME_PREFIX_ATTR属性中是否等于1b。如果是,则适用相同的规则。下列清单配置了 ReactiveLoadBalancerClientFilter:
例64.application.yml
spring:cloud:gateway:routes:- id: myRouteuri: lb://servicepredicates:- Path=/service/**
注意
默认情况下,当 ReactorLoadBalancer无法找到服务实例时,将返回 503。您可以通过设置 spring.cloud.gateway.
loadbalancer.use404=true来配置网关返回404。
uri地址修改为动态获取
解决uri写死问题
9527修改前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/**              # 断言,路径相匹配的进行路由
9527修改后的YML
#uri: http://localhost:8001                #匹配后提供服务的路由地址
uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
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/**              # 断言,路径相匹配的进行路由- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
测试1:
重启网关9527,80、8001保持不变
http://localhost/feign/pay/gateway/get/1
测试2:
如果将8001微服务ym1文件端口修改为8007,照样访问我实际启动的程序是main8001但是端口名改为8007
我们依据微服务名字, 匹配查找即可 uri: lb://cloud-payment-service

Predicate断言(谓词)

简介
官网地址: Spring Cloud Gateway
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合.
Route Predicate Factories(路由谓词工厂)是Spring Cloud Gateway中用于定义路由匹配条件的组件。它们允许您根据请求的不同属性(如路径、请求头、查询参数等)进行路由匹配,从而决定哪些请求应该被转发到特定的服务。
内置断言工厂介绍
Spring Cloud Gateway提供了多种内置的断言工厂,这些工厂允许您根据HTTP请求的不同属性来定义路由匹配条件。以下是一些常见的内置断言工厂:
  • PathRoutePredicateFactory:基于请求路径进行匹配。
  • MethodRoutePredicateFactory:基于HTTP请求方法进行匹配。
  • HeaderRoutePredicateFactory:基于请求头进行匹配,支持正则表达式。
  • QueryRoutePredicateFactory:基于查询参数进行匹配,支持正则表达式。
  • CookieRoutePredicateFactory:基于Cookie值进行匹配,支持正则表达式。
  • HostRoutePredicateFactory:基于请求的主机名进行匹配。
  • AfterRoutePredicateFactory、BeforeRoutePredicateFactoryBetweenRoutePredicateFactory:基于时间进行匹配,允许指定请求应该在某个时间之后、之前或两个时间之间才被路由。
  • RemoteAddrRoutePredicateFactory:基于客户端IP地址进行匹配,支持CIDR表示法。
启动微服务gateway9527查看IDEA后台的输出
常见的内置Route Predicate使用
  • 配置语法总体概述
  • 测试地址
  • 常用断言api
  • 上述配置小总结
配置语法总体概述
官网地址: https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.html
两种配置二选一
配置路由谓词工厂和网关过滤工厂
配置谓词和过滤器有两种方法:快捷方式和完全展开的参数。下面的大多数示例都使用快捷方式。
Shortcut Configuration 快捷方式
Fully Expanded Arguments 完全展开
测试地址: http://localhost:9527/pay/gateway/get/1
常用断言api:
#id:我们自定义的路由 ID,保持唯一
##uri:目标服务地址
##predicates:路由条件,Predicate接受一个输入参数返回一个布尔值。
##            该属性包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)
1.After Route Predicate (后路由谓词工厂)
After路由谓词工厂有一个参数,即 datetime(它是一个javaZonedDateTime)。该谓词匹配发生在指定datetime 之后的请求。
官网-Example 1. application
spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- After=2017-01-20T17:42:47.789-07:00[America/Denver]
具体代码实现: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                #匹配后提供服务的路由地址uri: lb://cloud-payment-service          #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: lb://cloud-payment-service           #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/info/**             # 断言,路径相匹配的进行路由
获取ZonedDateTime方式
package com.atguigu.test;
import java.time.ZoneId;
import java.time.ZonedDateTime;public class ZonedDateTimeDemo
{public static void main(String[] args){ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区System.out.println(zbj);}
}
2. Before Route Predicate(前路由谓词工厂)
Before 路由谓词工厂有一个参数,即 datetime(它是一个javaZonedDateTime)。该谓词匹配在指定日期时间之前发生的请求。
官网-Example 2. application.yml
spring:cloud:gateway:routes:- id: before_routeuri: https://example.orgpredicates:- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
3. Between Route Predicate(中间路由谓词工厂)
Between 路由谓词工厂有两个参数,datetimel和datetime2,它们是javaZonedDateTime对象。该谓词匹配发生在datetime1之后目在 datetime2之前的请求。datetime2参数必须在 datetime1之后。以下示例配置了一个 between路由谓词:
官网-Example 3. application.yml
spring:cloud:gateway:routes:- id: between_routeuri: https://example.orgpredicates:- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
4. Cookie Route Predicate (Cookie路线谓词工厂)
Cookie路由谓词工厂需要两个参数,即 cookie名称和正则表达式(即Java正则表达式)。该谓词匹配具有给定名称且值匹配正则表达式的 cookie。以下示例配置了一个 cookie 路由谓词工厂:
官网-Example 4. application.yml
spring:cloud:gateway:routes:- id: cookie_routeuri: https://example.orgpredicates:- Cookie=chocolate, ch.p
此路由可匹配包含名为chocolate的cookie的请求,该cookie的值与ch.p正则表达式匹配。
具体代码实现: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                #匹配后提供服务的路由地址uri: lb://cloud-payment-service          #匹配后提供服务的路由地址predicates:- Cookie=username,zzyy
测试方法1:原生命令
不带cookie参数   curl http://localhost:9527/pay/gateway/get/1
自带cookie参数   curl http://localhost:9527/pay/gateway/get/1 --cookie "username=zzyy"
测试方法2:postman
测试方法3:谷歌浏览器
5. Header Route Predicate(头文件路由谓词工厂)
Header路由谓词工厂需要两个参数:header和regexp(即Java正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的 header。以下示例配置了一个header 路由谓词:
官网-Example 5. application.yml
spring:cloud:gateway:routes:- id: header_routeuri: https://example.orgpredicates:- Header=X-Request-Id, \d+
如果请求具有名为X-Request-ld的头部,其值与\d+正则表达式匹配(即其值为一个或多个数字),则此路由将匹配。
具体实现代码:
server:port: 9527
spring: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:- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
测试方法1:原生命令:
curl http://localhost:9527/pay/gateway/get/1 -H  "X-Request-Id:123456" 
curl http://localhost:9527/pay/gateway/get/1 -H  "X-Request-Id:abcd"
测试方法2:postman
上图正确,下图错误验证
6. Host Route Predicate (主机路由谓词工厂)
主机路由谓词工厂有一个参数:主机名模式列表。该模式是一个Ant风格的模式,以,作为分隔符。该谓词匹配与模式匹配的主机标头。以下示例配置了一个主机路由谓词:
官网-Example 6. application.yml
spring:cloud:gateway:routes:- id: host_routeuri: https://example.orgpredicates:- Host=**.somehost.org,**.anotherhost.org
URI模板变量(如{sub}.myhost.org)也被支持。
如果请求的 Host 标头值为 www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配。
这个谓词将 URI 模板变量(如前面的示例中定义的sub)作为名称和值的映射提取出来,并将其放置在ServerWebExchange.getAttributes()中,其中包含在ServerWebExchangeUtilS.URI TEMPLATE VARIABLES ATTRIBUTE.然后这些值可供GatewayFilter工厂使用
具体代码实现:yml
server:port: 9527
spring: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:- Host=**.atguigu.com

测试方法1:原生命令
正确:     curl http://localhost:9527/pay/gateway/get/3 -H  "Host:www.atguigu.com"
正确:     curl http://localhost:9527/pay/gateway/get/3 -H  "Host:java.atguigu.com"
错误:     curl http://localhost:9527/pay/gateway/get/3 -H  "Host:java.atguigu.net"
测试方法2:postman
7.Method Route Predicate(方法路由谓语工厂)
方法路由谓词工厂接受一个方法参数,该参数是一个或多个参数:要匹配的HTTP方法。下面的示例配置一个方法路由:
Example 7. application.yml
spring:cloud:gateway:routes:- id: method_routeuri: https://example.orgpredicates:- Method=GET,POST
如果请求方法是GET或POST,则此路由将匹配。
备注:配置某个请求地址,只能用Get/Post方法访问,进行方法限制
8. Path Route Predicate (路径路由谓词工厂)
路径路由谓词工厂有两个参数:SpringPath Matcher模式的列表和一个名为 matchTrailingSlash 的可选标志(默认为 true)。以下示例配置了一个路径谓词:
官网-Example 8. application.yml
spring:cloud:gateway:routes:- id: path_routeuri: https://example.orgpredicates:- Path=/red/{segment},/blue/{segment}
如果请求路径是/red/1或/red/1/或/red/blue或/blue/green,则此路径将匹配。
如果matchTrailingSlash设置为false,则将不匹配请求path/red/1/。
这个谓词提取 URI模板变量(如前面的示例中定义的segment)作为名称和值的映射,并将其放置在 ServerWebExchange.getAttributes()中,其中包含在
ServerWebExchangeUtilS.URI TEMPLATE VARIABLES属性。然后这些值可供GatewayFilter工厂使用
可以使用一个实用程序方法(称为get),以便更容易地访问这些变量,下面的示例演示如何使用get方法:
MapuriVariables=ServerWebExchangeUtils.getUriTemplateVariables (exchange);字符串segment=uriVariables.get("segment");
具体代码实现:yml
server:port: 9527
spring: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/**              # 断言,路径相匹配的进行路由

9. Query Route Predicate(查询路由谓词工厂)
支持传入两个参数,一个是属性名,一个为属性值,属性值可以是正则表达式。
查询路由谓词工厂接受两个参数:一个必需参数和一个可选regexp(一个Java正则表达式)。下面的示例配置查询路由的谓词:
官网- Example 9. application.yml
spring: cloud: gateway: routes: - id: query_route uri: https://example.org predicates: - Query=green
如果请求包含绿色查询参数,则前面的路由将匹配
application.yml
spring:cloud:gateway:routes:- id: query_routeuri: https://example.orgpredicates:- Query=red, gree.
如果请求包含一个红色查询参数,其值与gree.regexp匹配,则前面的路由将匹配,因此greet将匹配。
具体代码实现:yml
server:port: 9527
spring: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:- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
10.RemoteAddr route predicate(远程地址路由谓词工厂)
RemoteAddr路由谓词工厂接受一个源列表(最小大小为1),它是CIDR标记(IPV4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。下面的示例配置了RemoteAddr路由谓词:
官网-Example 10. application.yml
spring:cloud:gateway:routes:- id: remoteaddr_routeuri: https://example.orgpredicates:- RemoteAddr=192.168.1.1/24
如果请求的远程地址为192.168.1.10,则此路由将匹配。
具体代码实现:yml
server:port: 9527
spring: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:- RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
CIDR网路IP划分(无类别域间路由Classless Inter-Domain Routing缩写)
上述配置小总结
Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
具体内置路由代码总结:
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/**              # 断言,路径相匹配的进行路由
自定义断言,XXXRoutePredicateFactory规则
自定义RoutePredicateFactory实现方式
AfterRoutePredicateFactory源码
模板方式:
  1. 要么继承AbstractRoutePredicateFactory抽象类
  2. 要么实现RoutePredicateFactory接
  3. 开头任意取名,但是必须以RoutePredicateFactory后缀结尾
自定义路由断言规则步骤套路
编写步骤
1.新建类名XXX需要以RoutePredicateFactory结尾并继承AbstractRoutePredicateFactory类
2.重写apply方法
3.新建apply方法所需要的静态内部类MyRoutePredicateFactory.Config,这个Config类就是我们的路由断言规则,重要
4.空参构造方法,内部调用super
5.重写apply方法第二版
1.新建类名XXX需要以RoutePredicateFactory结尾并继承AbstractRoutePredicateFactory类
@Component标注不可忘
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{
}
2.重写apply方法
@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;}};
}
完整代码
package com.atguigu.cloud.mygateway;
import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import java.util.function.Predicate;@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{public MyRoutePredicateFactory(){super(MyRoutePredicateFactory.Config.class);}@Validatedpublic static class Config{@Setter@Getter@NotEmptyprivate String userType; //钻、金、银等用户等级}@Overridepublic 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;}};}
}
测试1
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                #匹配后提供服务的路由地址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 表示法。- My=diamond- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
启动后
故障现象
org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under '' to com.atguigu.cloud.mygateway.MyRoutePredicateFactory$Config
Caused by: org.springframework.boot.context.properties.bind.validation.BindValidationException: Binding validation errors on 
导致原因
为什么Shortcut Configuration不生效?
解决方案
先解决问题,让我们自定义的能用
Fully Expanded Arguments YML
server:port: 9527
spring: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 表示法。#- My=diamond- name: Myargs:userType: diamond- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
http://localhost:9527/pay/gateway/get/1?userType=diamond
成功
bug分析
缺少shortcutFieldOrder方法的实现,所以不支持短格式
测试2
完整代码02
package com.atguigu.cloud.mygateway;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{public MyRoutePredicateFactory(){super(MyRoutePredicateFactory.Config.class);}@Validatedpublic static class Config{@Setter@Getter@NotEmptyprivate String userType; //钻、金、银等用户等级}@Overridepublic 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;}};}@Override
public List<String> shortcutFieldOrder() {return Collections.singletonList("userType");
}}
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                #匹配后提供服务的路由地址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 表示法。- My=diamond#- name: My#  args:#    userType: diamond- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
重启9527并测试
http://localhost:9527/pay/gateway/get/1?userType=diamond

Filter过滤

概述
官网地址: Spring Cloud Gateway
Gateway过滤器工厂
路由过滤器允许以某种方式修改传入的HTTP请求或发出的HTTP响应。路由过滤器被限制在特定的路由上。SpringCloud Gateway包含许多内置的GatewayFilter工厂。
springMVC里面的的拦截器Interceptor,Servlet的过滤器
“pre”和“post”分别会在请求被执行前调用和被执行后调用用来修改请求和响应信息。
作用:
  • 请求鉴权
  • 异常处理
  • 记录接口调用时长统计
类型:
1.全局默认过滤器Global Filters
官网地址: Spring Cloud Gateway
gateway出厂默认已有的,直接用即可,主要作用于所有的路由不需要在配置文件中配置,作用在所有的路由上,实现GlobalFilter接口即可
2.单一内置过滤器GatewayFilter(共38个)
官网地址: Spring Cloud Gateway
也可以称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由分组
3. 自定义过滤器
Gateway内置的过滤器
1.请求头(RequestHeader)相关组
添加、删除、修改请求头
6.1.The AddRequestHeader GatewayFilter Factory(添加请求头网关过滤器工厂)
  1. 指定请求头内容ByName
  2. 8001微服务PayGateWayController新增方法
package com.atguigu.cloud.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.service.PayService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Enumeration;/*** Gateway网关——路由映射 实例**/
@RestController
public class PayGateWayController {@ResourcePayService payService;@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-red")|| headName.equalsIgnoreCase("X-Request-blue")) {result = result+headName + "\t " + headValue +" ";}}return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}
}

3.9527网关YML添加过滤内容

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

4.重启9527和8001并再次调用地址

访问地址: http://localhost:9527/pay/gateway/filter
6.18.The RemoveRequestHeader GatewayFilter Factory(移除请求头网关过滤器工厂)
  1. 删除请求头ByName
  2. 修改前

3.YML 

- RemoveRequestHeader= sec-fetch-site       # 删除请求头sec-fetch-site
spring:cloud:gateway:routes:- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site

4.重启9527和8001并再次调用地址

http://localhost:9527/pay/gateway/filter

5.修改后

6.29.The SetRequestHeader GatewayFilter Factory(设置请求头网关过滤器工厂)
  1. 修改请求头ByName
  2. 修改前(sec-fetch-mode)

3.YML参数设置

- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy  # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy

4.重启9527和8001并再次调用地址

访问地址: http://localhost:9527/pay/gateway/filter

5.修改后

2.请求参数(RequestParameter)相关组
6.3 The AddRequestParameter GatewayFilter Factory(添加请求参数网关过滤器工厂)
- AddRequestParam=customerId,9527001 #新增请求参数Parameter:k,v
6.19 The RemoveRequestParamter GatewayFilter Factory(移除请求参数网关过滤器工厂)
- RemoveRequestParameter=customerName=customerName #删除url请求参数 customerName,你传递过来也是null
请求参数示例(6.3/6.19):
1.YML参数设置
- AddRequestParameter=customerId,9527001 #新增请求参数Parameter:k,v
- RemoveRequestParameter=customerName #删除url请求参数customerName,设置后传递过来也是null
spring:cloud:gateway:routes:- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestParameter=customerId,9527001 #新增请求参数Parameter:k,v- RemoveRequestParameter=customerName    #删除url请求参数customerName,设置后传递过来也是null
2.修改PayGateWayController
@GetMapping(value = "/pay/gateway/filter")
public ResultData<String> getGatewayFilter(HttpServletRequest request)
{System.out.println("=============================================");String customerId = request.getParameter("customerId");System.out.println("request Parameter customerId:"+customerId);String customerName = request.getParameter("customerName");System.out.println("request Parameter customerName:"+customerName);System.out.println("=============================================");return ResultData.success("getGatewayFilter 新增/删除请求参数 ");
}
3.测试访问
访问地址1: http://localhost:9527/pay/gateway/filter
默认访问参数值:
AddRequestParameter=customerId 参数值为设置的参数值:9527001
RemoveRequestParameter=customerName 参数值为 null
访问2地址: http://localhost:9527/pay/gateway/filter?customerId=9999&customerName=z3
带参数访问:
AddRequestParameter=customerId 参数值为设置的参数值:9999,会根据传递的参数值进行变化
RemoveRequestParameter=customerName 参数值为 null————物理是否传参数,参数值都会根据gateway配置设置为null
3.回应头(ResponseHeader)相关组
开启配置前,按照地址chrome查看一下: http://localhost:9527/pay/gateway/filter
6.4 The AddResponseHeader GatewayFilter Factory(新增响应头网关过滤器工厂)
AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
6.30 The SetResponseHeader GatewayFilter Factory(设置/修改响应头网关过滤器工厂)
SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
6.20 The RemoveResponseHeader GatewayFilter Factory(移除响应头网关过滤器工厂)
RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
请求参数示例(6.4/6.30/6.20):
YML参数设置:
- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
spring:cloud:gateway:routes:- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
开启配置后,上面打包运行结果:
4.前缀和路径相关组
6.14.The PrefixPath GatewayFilter Factory(前缀路径网关过滤器工厂)
该过滤器的作用:自动添加路径前缀
YML参数配置
- Path=/gateway/filter/**      # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
- PrefixPath=/pay  # http://localhost:9527/pay/gateway/filter
分拆说明:
官方示例:
spring:cloud:gateway:routes:- id: prefixpath_routeuri: https://example.orgfilters:- PrefixPath=/mypath
向/hello路径访问,实际会访问/mypath/hello地址
之前完整正确地址:
http://localhost:9527/pay/gateway/filter
现在完整组合地址:
PrefixPath + Path
实际调用地址:
http://localhost:9527/gateway/filter
相当于说前缀被过滤器统一管理了。
Chrome测试:
实现效果:前缀路径被过滤器 进行统一管理了。
访问 http://localhost:9527/gateway/filter 即可实现对系统内部 http://localhost:9527/pay/gateway/filter的访问,/pay被配置到filter里面了
6.29.The SetPath GatewayFilter Factory(设置路径网关过滤器工厂)
作用:访问路径修改
测试:
YML参数设置(带占位符的地址替换)
- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
- SetPath=/pay/gateway/{segment} # {segment}表示占位符,你写abc也行但要上下一致
spring:cloud:gateway:routes:- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- SetPath=/pay/gateway/{segment} # {segment}表示占位符,你写abc也行但要上下一致
说明:
/XYZ/abc/{segment}
{segment}就是个占位符,等价于SetPath后面指定的{segment}内容
浏览器访问地址: http://localhost:9527/XYZ/abc/filter 
实际微服务地址: http://localhost:9527/pay/gateway/filter
访问结果:
6.16.The RedirectTo GatewayFilter Factory(重定向到网关过滤器工厂)
本过滤器作用:重定向到某个页面
YML参数配置:
spring:cloud:gateway:routes:- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- RedirectTo=302, http://www.baidu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.baidu.com/

访问效果:访问该地址直接跳转到RedirTo设置的网址。
5. 其它
6.38. Default Filters(默认全局过滤器)
配置在此处相当于全局通用
要添加筛选器并将其应用于所有路由,可以使用spring.cloud.gateway.default-filters。此属性接受筛选器列表。以下列表定义了一组默认过滤器:
spring:cloud:gateway:default-filters:- AddResponseHeader=X-Response-Default-Red, Default-Blue- PrefixPath=/httpbin
Default Filters 将设置的过滤器进行全局共用,一般不推荐直接全局使用,还是根据过滤地址,进行细颗粒的配置比较常用。
本次案例全部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                #匹配后提供服务的路由地址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 表示法。- My=gold
#            - name: My
#              args:
#                userType: diamond- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址#- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay#- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- RedirectTo=302, http://www.atguigu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/#- SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致#- PrefixPath=/pay # http://localhost:9527/pay/gateway/filter  被分拆为: PrefixPath + Path#- 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回应属性删除
Gateway自定义过滤器
自定义全局Filter
面试题
统计接口调用耗时情况,如何落地,谈谈设计思路
答案:通过自定义全局过滤器搞定上述需求
官方介绍
官方地址: Spring Cloud Gateway
自定义全局Filter简介:
当请求与路由匹配时,过滤Web处理程序会将所有GlobalFilter实例和所有特定于路由的Gatewavfilter实例添加到过滤链中。这个组合的 过滤链按org.springframework.core.0rdered接口排序,您可以通过实现getOrder ()方法来设置
由于Spring cloud Gateway区分过滤逻辑执行的“前”和“后”阶段(参见其工作原理),优先级最高的过滤器在“前阶段中是第一个,在“后”阶段中是最后一个。
示例
1.步骤:
新建类MyGlobalFilter并实现GlobalFilter,Ordered两个接囗
package com.atguigu.cloud.mygateway;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){return null;}@Overridepublic int getOrder(){return 0;}
}
2.YML参数配置
作用范围: gateway全局路径相匹配的进行路由进行过滤统计。
 predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
 predicates:
            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
 predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
server:port: 9527
spring: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,若一头含有多参则重写一行设置
3.code - MyGlobalFilter 参数配置
package com.atguigu.cloud.mygateway;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@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.测试地址:
http://localhost:9527/pay/gateway/info
http://localhost:9527/pay/gateway/get/1
http://localhost:9527/pay/gateway/filter
自定义条件Filter
自定义条件Filter解释:自定义,单一内置过滤器GatewayFilter
先参考GateWay内置出厂默认的过滤器
  • SetStatusGatewayFilterFactory
  • SetPathGatewayFilterFactory
  • AddResponseHeaderGatewayFilterFactory
自定义网关过滤器规则步骤套路

1.新建类名XXX需要以GatewayFilterFactory结尾并继承AbstractGatewayFilterFactory类

@Component //标注不可忘
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
}

2.新建xxXGatewayFilterFactory.config内部类

public static class Config{@Setter@Getterprivate String status;
}

3.重写apply方法

package com.atguigu.cloud.MyGlobalFilter;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
/*** 自定义网关过滤器规则*/
@Component //标注不可忘
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {@Overridepublic GatewayFilter apply(MyGatewayFilterFactory.Config config){return new GatewayFilter(){@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("进入自定义网关过滤器MyGateWayFilter,status==="+config.getStatus());if(request.getQueryParams().containsKey("atuguigu")){return chain.filter(exchange);}else{exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}public static class Config{@Setter@Getterprivate String status;}
}

4.重写shortcutFieldOrder

@Override
public List<String> shortcutFieldOrder() {List<String> list = new ArrayList<String>();list.add("status");return list;
}

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

//空参构造方法,内部调用super
public MyGatewayFilterFactory(){super(MyGatewayFilterFactory.Config.class);
}

6.完整代码01

package com.atguigu.cloud.MyGlobalFilter;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.ArrayList;
import java.util.List;/*** 自定义网关过滤器规则* 参考GateWay内置出厂默认的过滤器,继承 AbstractGatewayFilterFactory类* - SetStatusGatewayFilterFactory* - SetPathGatewayFilterFactory* - AddResponseHeaderGatewayFilterFactory*/
@Component //标注不可忘
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {//空参构造方法,内部调用superpublic MyGatewayFilterFactory(){super(MyGatewayFilterFactory.Config.class);}//重写apply方法 该方法内部重新定义规则@Overridepublic GatewayFilter apply(MyGatewayFilterFactory.Config config){return new GatewayFilter(){@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("进入自定义网关过滤器MyGateWayFilter,status==="+config.getStatus());if(request.getQueryParams().containsKey("atuguigu")){return chain.filter(exchange);}else{exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}//重写shortcutFieldOrder@Overridepublic List<String> shortcutFieldOrder() {List<String> list = new ArrayList<String>();list.add("status");return list;}public static class Config{@Setter@Getterprivate String status;}
}
YML 参数配置
出产默认
自定制My
测试
访问测试(未携带atguigu参数进行访问): http://localhost:9527/pay/gateway/filter
访问测试(携带atguigu参数进行访问): http://localhost:9527/pay/gateway/filter?atguigu=java
Gateway整合阿里巴巴Sentinel实现容错---见后续springcloud alibaba篇章

相关知识拓展:

CIDR(无类域间路由)
CIDR(Classless Inter-Domain Routing,无类域间路由)是一种用于划分和分配IP地址的方法,其核心思想是将IP地址划分为前缀和后缀两部分,其中前缀表示网络的标识,而后缀表示主机的标识。CIDR的引入旨在更灵活地分配IP地址,并更有效地利用地址空间。以下是对CIDR网络IP划分的详细解释:
CIDR表示法
CIDR使用“IP地址/前缀长度”的格式来表示一个IP地址范围。例如,192.168.1.0/24表示一个IP地址块,其中192.168.1.0是网络的基本地址,/24表示前缀长度为24位,即前24位用于网络标识,剩余的8位用于主机标识。
划分过程
1.确定IP地址范围:
- 首先,需要确定需要划分的IP地址范围。
2.确定网络前缀长度:
- 根据需要划分的子网数量,确定划分后的网络前缀长度。网络前缀长度可以是任意值,从1到32。前缀长度越长,可分配的子网数量就越多,但每个子网中的主机数量就越少。
3.划分子网:
- 根据网络前缀长度,将IP地址划分为多个子网。划分时,将IP地址的二进制形式按照网络前缀长度进行分割,前面的部分是网络部分,后面的部分是主机部分。
4.分配网络地址:
- 为每个子网分配一个唯一的网络地址,通常是网络部分的第一个IP地址。
5.分配主机地址:
- 根据需要,为每个子网分配一定数量的IP地址,用于分配给主机。
6.确定子网掩码:
- 子网掩码用于划分网络部分和主机部分。在CIDR中,子网掩码的长度直接由前缀长度决定。
示例
- 假设有一个CIDR地址块192.168.1.0/24,这个地址块包含了从192.168.1.0到192.168.1.255的所有主机。
- 如果想要将这个地址块划分为两个子网,可以选择将前缀长度增加1位,即划分为192.168.1.0/25和192.168.1.128/25两个子网。其中,192.168.1.0/25包含了从192.168.1.0到192.168.1.127的地址,而192.168.1.128/25包含了从192.168.1.128到192.168.1.255的地址。
优点:
- 灵活性:CIDR允许更灵活地分配IP地址,可以根据实际需求划分不同大小的子网。
- 高效性:CIDR减少了路由表的大小,提高了路由效率。通过聚合多个子网到一个CIDR块中,可以减少路由表中的条目数量。
- 节省地址空间:CIDR避免了固定类别IP地址分配方案中的地址浪费问题,可以更有效地利用IP地址空间。
总之,CIDR网络IP划分是一种灵活且高效的IP地址分配方法,它通过引入前缀长度的概念,使得IP地址的分配更加灵活和高效。

http://www.hkcw.cn/article/NxvgPSarYF.shtml

相关文章

雷军刚学的莫言名言不是莫言说的 小米华为汽车大乱斗

#雷军疑似回应余承东#喷了,雷军把自己的微博编辑了,去掉「刚学会一句莫言名言:诋毁,本身就是一种仰望」这句心灵鸡汤了。这波小米华为汽车大乱斗,整的乐子有点大啊,感谢今天儿童节贡献的欢乐[doge]“莫言说:诋毁,本身就是一种仰望。”小米卢伟冰在社交媒体上的这句话,…

广东本月起在8市启动住院免陪护试点 缓解家庭陪护压力

俗话说“久病床前无孝子”,这句话道出了很多家庭面对病人陪护时的无奈与压力。特别是随着老龄化问题日益严重,独生子女家庭在父母住院时面临的陪护难题更加突出。如果医院能够提供标准化的照护服务,将大大缓解这一困境。国家卫健委等三部委已印发方案,将在6月全国范围内开展…

AI炼丹日志-22 - MCP 自动操作 Figma+Cursor 自动设计原型

MCP 基本介绍 官方地址&#xff1a; https://modelcontextprotocol.io/introduction “MCP 是一种开放协议&#xff0c;旨在标准化应用程序向大型语言模型&#xff08;LLM&#xff09;提供上下文的方式。可以把 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 提供了一种…

数字化赋能风电未来:视频监控+应急管理系统破解边远基站无人值守难题

引言&#xff1a;风电行业的新挑战与数字化机遇 随着我国风电产业的高速发展&#xff0c;越来越多的风电场建在边远山区、荒漠或海上&#xff0c;这些区域环境恶劣、交通不便&#xff0c;传统人工巡检模式成本高、效率低&#xff0c;且存在安全隐患。如何实现风电基站的无人化…

45岁陈冠希咖啡店被偶遇 悠闲生活羡煞旁人

陈冠希和超模秦舒培结婚后,育有一个8岁的女儿。现在他们一家三口定居在日本东京中目黑。陈冠希经常光顾当地的一家咖啡店,多次被民众偶遇。5月31日,陈冠希再次出现在这家咖啡店,并被认出。当天他穿着自家潮牌设计的衣服,看起来很随性,但穿搭并不十分时尚。他的状态还不错…

关之琳62岁状态极佳 港圈传奇女神依旧风采

关之琳近日出席活动状态极佳,疑似与前任马清伟、刘銮雄同场也不尴尬,更与马清伟现任女友大方合影。62岁仍保持完美身材和冻龄美貌,不愧是港圈传奇女神!责任编辑:zx0001

UDOP:统一视觉、文本与版式的信息以实现通用文档处理

摘要 我们提出了通用文档处理&#xff08;UDOP&#xff09;模型&#xff0c;一种基础的文档人工智能模型&#xff0c;它将文本、图像和布局模态与多种任务格式统一在一起&#xff0c;包括文档理解和生成。UDOP利用文本内容与文档图像之间的空间关联&#xff0c;通过一种统一的…

新理财手段突然爆火 谷子经济引关注

谷子的授权溢价、金融化泡沫、炒作乱象以及涉黄等法律风险,成为产业升级道路上的现实难题。“一块‘吧唧’(徽章)被炒到7万多”登上热搜后,公众开始对谷子经济有了全新的认知和理解。这款在二手平台上被炒到7.2万元的“吧唧”,是《排球少年!!》里西谷夕的角色。这款徽章…

《全员加速中》苏醒最后一秒被抓 再就业男团欢乐互动

再就业男团再次给观众带来欢乐。《快乐再出发》第三季结束后,他们合体次数不多,但苏醒的分享欲很强,在社交账号上频繁更新与成员们的互动消息,总能逗乐大家。最近,苏醒参加了新一期《全员加速中》的录制。他本想好好表现一番,结果刚一开工就被猎人抓到中止间,体验感直接…

雷军透露小米YU7预计7月量产 全力准备中

6月1日,雷军在微博上宣布,2025年5月小米SU7的交付量将超过28000台。他同时透露,公司正在全力准备小米YU7的大规模量产,预计将在7月份开始。雷军还提到,他刚学会了一句莫言的名言:诋毁,本身就是一种仰望。此前一天,小米集团合伙人、总裁卢伟冰也引用了这句名言。他表示,…

俄罗斯桥梁坍塌 火车脱轨扭成麻花 事故致7死数十伤

俄罗斯西部布良斯克州一座桥梁于5月31日晚发生坍塌,导致一列客运火车脱轨。布良斯克州长博戈马兹表示,该事件已造成至少7人死亡,另有数十人受伤。救援现场的照片显示了事故后的紧急救援情况。责任编辑:zx0001

小米多位高管集体发声 全力准备小米yu7量产

6月1日,雷军发文称,小米正在全力为小米yu7的大规模量产做准备,预计在7月份实现量产。他还引用了莫言的一句话:诋毁,本身就是一种仰望。5月31日,卢伟冰表示,无论是SU7的热销还是YU7获得比SU7更高的关注和期待,都是基于强大的产品力。他强调,小米汽车的成功源于小米的价…

德约科维奇3-0横扫进法网16强 轻松晋级展现实力

北京时间6月1日,法网男单第三轮比赛中,赛会6号种子德约科维奇对阵世界排名153位的米索里奇。德约科维奇全程占据优势,以3-0轻松战胜对手晋级。比赛开始后,德约科维奇率先保发。第二局中,尽管他逼出了三个破发点但未能把握住机会,双方经过多次平分后米索里奇艰难保发。德约…

歼20垂直起降 假照片引发热议

近日,在国内知名军事资讯节目《军武次位面》的评论区,有网友分享了一张据称是“歼-20垂直起降型战机试飞”的照片。许多自媒体和营销号也借此机会大做文章,声称中国的歼-20垂直起降版本已经进行了试飞。这张照片展示了一架歼-20战机的外形,并且可以看到一个类似F-35B垂直起…

日本水产品想恢复入华?中方回应 技术交流取得进展

5月30日,外交部发言人林剑主持例行记者会。有记者提问,据了解,5月28日,中国海关总署同日方就日本水产品安全问题进行了技术交流,希望了解相关情况。林剑表示,今年中方在持续开展对福岛核污染水排海国际监测并独立取样检测结果没有异常的基础上,与日方就日本水产品安全问…

国际奥委会发盛李豪霹雳舞视频 射击冠军跨界热舞

6月1日,奥林匹克运动会发布了一段盛李豪跳霹雳舞的视频。视频中,他表示希望能与巴黎奥运会霹雳舞B-Girls铜牌得主刘清漪一起跳舞。盛李豪2004年出生于江苏苏州张家港市,13岁开始接触射击。2018年他入选江苏省射击队,次年又进入了国家队。在2020年的东京奥运会上,首次参赛的…

余承东:不能为低成本而牺牲质量 质量是生命线

华为常务董事、终端BG董事长余承东在今日的未来汽车先行者大会上表示,华为采用的宁德时代电池已经提前五年达到了新的国家标准。他强调,在华为的质量标准体系下,有些车企甚至无法出货一台车。余承东呼吁大家重视产品质量,不要为了过分追求低成本而牺牲质量。他认为,质量是…

李健演唱会遇暴雨全程不打伞 敬业精神感动歌迷

李健的巡回演唱会在各地都受到了热烈欢迎。然而,在5月31日晚嘉兴站的演出中,天空突然下起了大雨。尽管如此,李健依然坚持在雨中完成表演,他的敬业精神让人感动。当晚,暴雨如注,李健的衣服和头发都被淋湿,雨水顺着脸颊流下,但这些都没有影响他与歌迷的热情互动。李健的妻…

消费者从黄金“转战”铂金 投资新宠崛起

陈女士是一位热衷于投资的人,最近她在铂金市场上进行了大额投资。她认为铂金市场出现了缺货和抢货现象,且铂金价格在底部徘徊多年,上涨概率较大。4月2日,她以接近120万元的资金购买了10斤铂金条和铂金板料。5月下旬,铂金价格迅速上涨,纽约商品交易所的铂金期货主力合约一…

作业长度与页号位数的关系

作业长度&#xff08;6 页&#xff09;与页号位数的关系&#xff1a;页号位数≥最大页号所需位数 作业长度 6 页意味着页号范围是 0~5&#xff08;共 6 页&#xff09;&#xff0c;理论上 3 位二进制&#xff08;28≥6&#xff09;即可表示。但由题目算得页号占 5 位&#xff…