当前位置: 首页 > news >正文

SpringCloud-快速通关(二)

SpringCloud-快速通关(一)

SpringCloud-快速通关(二)

SpringCloud-快速通关(三)

SpringCloud-快速通关(二)

  • 四、OpenFeign - 远程调用
    • 4.1、基础入门
    • 4.2、进阶配置
      • 4.2.1、开启日志
      • 4.2.2、超时控制
      • 4.2.3、重试机制
      • 4.2.4、fallback - 兜底返回
  • 五、Sentinel - 流量保护
    • 5.1、介绍
    • 5.2、架构
    • 5.3、资源&规则
    • 5.4、环境搭建
    • 5.5、异常处理
      • 5.5.1、Web接口出现异常(自定义 BlockExceptionHandler)
      • 5.5.2、@SentinelResource出现异常(blockHandler)
      • 5.5.3、OpenFeign调用出现异常
      • 5.5.4、SphU 硬编码 出现异常
    • 5.6、规则 - 流量控制
      • 5.6.1、阈值类型
      • 5.6.2、集群
      • 5.6.2、流控模式
      • 5.6.3、流控效果
    • 5.7、规则 - 熔断降级
      • 5.7.1、断路器
      • 5.7.2、工作原理
      • 5.7.3、熔断与兜底
      • 5.7.4、熔断策略
    • 5.8、规则 - 热点参数
  • 六、Gateway - 网关
    • 6.1、基础入门
      • 6.1.1、功能
      • 6.1.2、原理
      • 6.1.3、环境配置
    • 6.2、Predicate - 断言
    • 6.3、Filter - 过滤器
    • 6.4、CORS - 跨域处理
    • 6.5、GlobalFilter

四、OpenFeign - 远程调用

4.1、基础入门

  • 简介

官网:https://docs.spring.io/spring-cloud-openfeign/reference/spring-cloud-openfeign.html#spring-cloud-feign

OpenFeign 是一个声明式远程调用客户端;区别于:restTemplate是编程式远程调用;

在这里插入图片描述

  • 基础使用

引入依赖

由于大型项目中,每个项目都可能需要使用远程调用。所以我们可以在父项目中统一引入

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

开启功能

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

远程调用

@FeignClient("stores")
public interface StoreClient {@RequestMapping(method = RequestMethod.GET, value = "/stores")List<Store> getStores();@GetMapping("/stores")Page<Store> getStores(Pageable pageable);@PostMapping(value = "/stores/{storeId}", consumes = "application/json",params = "mode=upsert")Store update(@PathVariable("storeId") Long storeId, Store store);@DeleteMapping("/stores/{storeId:\\d+}")void delete(@PathVariable Long storeId);
}

注意用法:
@EnableFeignClients
@EnableFeignClients(basePackages = “com.example.clients”)

  • 详细用法

在这里插入图片描述
services中导依赖

<!--openfeign-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类加注解@EnableFeignClients(value = "com.atguigu.order.feign")

编写FeignClient接口 远程调用方法直接将调用地方的controller方法粘贴过来即可

@FeignClient(value = "service-product")
public interface ProductFeignClient {@GetMapping(value = "/productId/{id}")public Product getProductById(@PathVariable("id") Long productId);
}

改造service-order OrderServiceImpl

@Autowired
ProductFeignClient productFeignClient;Product product = productFeignClient.getProductById(productId);

在这里插入图片描述

远程调用外部API

在这里插入图片描述
feign接口

@FeignClient(value = "weather-client", url = "http://aliv18.data.moji.com")
public interface WeatherFeignClient {@PostMapping("/whapi/json/alicityweather/condition")String getWeather(@RequestHeader("Authorization") String auth,@RequestParam("token") String token,@RequestParam("cityId") String cityId);
}

测试方法

@SpringBootTest
public class WeatherTest {@AutowiredWeatherFeignClient weatherFeignClient;@Testpublic void test() {String weather = weatherFeignClient.getWeather("自己的AppCode","50b53ff8dd7d9fa320d3d3ca32cf8ed1","2182");System.out.println("weather = " + weather);}
}

测试效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 客户端负载均衡:客户端在选择服务地址进行调用,例如service-order掉多个service-product

  • 服务端负载均衡:服务端进行负载均衡,客户端只要发请求即可,例如调用墨迹天气API

4.2、进阶配置

4.2.1、开启日志

logging:level:com.atguigu.order.feign: debug
@Bean
Logger.Level feignLoggerLevel() {return Logger.Level.FULL;
}

在这里插入图片描述
application.yml中开启日志

说明: 这行配置是 Spring Boot 的日志配置,用于设置 com.atguigu.order.feign 这个包下的 日志级别 为 DEBUG。

logging:level:com.atguigu.order.feign: debug

OrderConfig中设置日志信息

说明:这是 Feign 提供的日志级别配置,它控制 Feign 请求和响应的详细日志,Logger.Level.FULL 代表 打印所有请求和响应的详细信息

  • 请求方法(GET、POST等)
  • 请求URL
  • 请求头
  • 请求体
  • 响应状态码
  • 响应头
  • 响应体
  • 请求的执行时间
@Bean
Logger.Level feignLoggerLevel() {return Logger.Level.FULL;
}

4.2.2、超时控制

spring:cloud:openfeign:client:config:default:logger-level: fullconnect-timeout: 1000read-timeout: 2000service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000

在这里插入图片描述
在这里插入图片描述
application.yml引入application-feign.yml

在这里插入图片描述
添加application-feign.yml

spring:cloud:openfeign:client:config:default:logger-level: fullconnect-timeout: 1000read-timeout: 2000service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000

源码

在这里插入图片描述

service-product中模拟超时,后续记得去掉

try {TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();
}

在这里插入图片描述

效果

在这里插入图片描述

4.2.3、重试机制

@Bean
Retryer retryer(){return new Retryer.Default();
}

在这里插入图片描述
service-orderOrderConfig中加入重试机制

@Bean
Retryer retryer() {return new Retryer.Default();
}

源码:默认重试5次,初始间隔100毫秒,后续每次乘1.5,最多间隔1秒

在这里插入图片描述

拦截器

在这里插入图片描述

全局拦截器——拦截所有远程调用请求

响应拦截器用的不多,请求拦截器多

service-order 的包下 com.atguigu.order.interceptor

@Component
public class XTokenRequestIntercepter implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {requestTemplate.header("X-Token", UUID.randomUUID().toString());}
}

改造service-productProductController

@RestController
public class ProductController {@AutowiredProductService productService;@GetMapping(value = "/productId/{id}")public Product getProductById(@PathVariable("id") Long productId, HttpServletRequest httpServletRequest) {String XToken = httpServletRequest.getHeader("X-Token");System.out.println("XToken = " + XToken);System.out.println("正在远程调用service-product...");//        int i = 10 / 0;Product product = productService.getProductById(productId);return product;}
}

效果

在这里插入图片描述

局部拦截器

在这里插入图片描述
测试

实验一:拦截器不放入容器+配置定制拦截器

在这里插入图片描述
效果:有效

在这里插入图片描述

实验二:拦截器不放入容器+不定制拦截器

在这里插入图片描述

效果:失败

在这里插入图片描述

4.2.4、fallback - 兜底返回

在这里插入图片描述

  1. 引入 sentinel
        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
  1. 开启熔断

application-feign.yml加配置

feign:sentinel:enabled: true
  1. 编写 fallback 函数

ProductFeignClient加上回调实现

@FeignClient(value = "service-product",fallback = ProductFeignClientFallback.class) // feign客户端
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1、标注在Controller上,是接收这样的请求//2、标注在FeignClient上,是发送这样的请求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);
}

ProductFeignClientFallback

@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getProductById(Long id) {System.out.println("兜底回调....");Product product = new Product();product.setId(id);product.setPrice(new BigDecimal("0"));product.setProductName("未知商品");product.setNum(0);return product;}
}

测试前先将重试机制关了,不然会一直重试,无法快速看到兜底结果。

在这里插入图片描述

测试:模拟远程调用失败

在调用service-productcontroller中加入一个错误。或者将service-order服务给停掉

在这里插入图片描述

在这里插入图片描述

小节

在这里插入图片描述

五、Sentinel - 流量保护

5.1、介绍

  • 官网:https://sentinelguard.io/zh-cn/index.html
  • wiki:https://github.com/alibaba/Sentinel/wiki
  • 下载控制台:sentinel-dashboard-1.8.8.jar

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
  • 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

在这里插入图片描述

5.2、架构

在这里插入图片描述

5.3、资源&规则

在这里插入图片描述

定义资源:

  • 主流框架自动适配(Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor);所有Web接口均为资源
  • 编程式:SphU API
  • 声明式:@SentinelResource

定义规则:

  • 流量控制规则
  • 熔断降级规则
  • 系统保护规则
  • 来源访问控制规则
  • 热点参数规则

在这里插入图片描述

5.4、环境搭建

  • 依赖

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 下载sentinel dashboard:sentinel-dashboard-1.8.8.jar

  • 启动:cmd输入:java -jar sentinel.jar;账号密码都是sentinel

  • 配置连接+热加载(服务启动就加载):

    spring.cloud.sentinel.transport.dashboard=localhost:8080
    spring.cloud.sentinel.eager=true
    

说明:簇点链路中的链路来自于几种资源:

  1. 主流框架自动适配(例如:web请求)
  2. 声明式 Sphu API(不常用)
  3. 声明式:@SentinelResource

在这里插入图片描述

5.5、异常处理

在这里插入图片描述

5.5.1、Web接口出现异常(自定义 BlockExceptionHandler)

model模块写异常类—模拟异常处理

@Data
public class R {private Integer code;private String msg;private Object data;public static R ok() {R r = new R();r.setCode(200);return r;}public static R ok(String msg,Object data) {R r = new R();r.setCode(200);r.setMsg(msg);r.setData(data);return r;}public static R error() {R r = new R();r.setCode(500);return r;}public static R error(Integer code,String msg) {R r = new R();r.setCode(code);r.setMsg(msg);return r;}
}

实现BlockExceptionHandler接口

service-ordercom.atguigu.order.exception包中写一个BlockExceptionHandler的实现类

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response,String resourceName, BlockException e) throws Exception {response.setStatus(429); //too many requestsresponse.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();R error = R.error(500, resourceName + " 被Sentinel限制了,原因:" + e.getClass());String json = objectMapper.writeValueAsString(error);writer.write(json);writer.flush();writer.close();}
}

配置流控规则

QPS设置每秒只允许1个请求

在这里插入图片描述
在这里插入图片描述

效果

在这里插入图片描述

违反流控规则就走MyBlockExceptionHandler异常

在这里插入图片描述

5.5.2、@SentinelResource出现异常(blockHandler)

在目标方法加@SentinelResource注解

在这里插入图片描述

编写blockHandler方法或者fallback方法处理异常

blockHandler="异常处理方法",这个方法中加参数: BlockException exception

fallback="异常处理方法",这个方法中加参数:Throwable exception

二者作用一样

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@AutowiredLoadBalancerClient loadBalancerClient;@AutowiredProductFeignClient productFeignClient;@SentinelResource(value = "createOrder",blockHandler = "createOrderFallback")@Overridepublic Order createOrder(Long userId, Long productId) {//        Product product = this.getProductFromRemote(productId);//        Product product = this.getProductFromRemoteWithLoadBalance(productId);//        Product product = this.getProductFromRemoteWithLoadBalanceAnnotation(productId);Product product = productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);// 总金额=价格*数量BigDecimal price = product.getPrice();//价格int num = product.getNum();//数量order.setTotalAmount(price.multiply(new BigDecimal(num)));//总价order.setUserId(userId);order.setNickName("张三");order.setAddress("火星");// 远程查询商品列表order.setProductList(Arrays.asList(product));return order;}public Order createOrderFallback(Long userId, Long productId, BlockException e) {Order order = new Order();order.setId(0L);order.setTotalAmount(new BigDecimal("0"));order.setUserId(userId);order.setNickName("未知用户");order.setAddress("异常信息" + e.getClass());return order;}//阶段三:于注解的负载均衡public Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId) {//给远程发送请求;;service-product会被动态替换String url = "http://service-product/productId/" + productId;Product product = restTemplate.getForObject(url, Product.class);return product;}}

测试

在这里插入图片描述
在这里插入图片描述

5.5.3、OpenFeign调用出现异常

走openfeign的fallback异常

在这里插入图片描述
在这里插入图片描述

5.5.4、SphU 硬编码 出现异常

暂时略…

5.6、规则 - 流量控制

在这里插入图片描述
application-feign.yml中加配置:

web-context-unify: false #在sentinel中不共用同一个上下文

在这里插入图片描述
在这里插入图片描述

5.6.1、阈值类型

  • QPS:统计每秒请求数
  • 并发线程数:统计并发线程数

5.6.2、集群

集群和流控模式是相背离的,二选一

在这里插入图片描述

5.6.2、流控模式

在这里插入图片描述

流控模式——直接策略:只对一个资源进行控制

流控模式——链路策略

@GetMapping("/seckill")
public Order seckill(@RequestParam("userId") Long userId,@RequestParam("productId") Long productId) {Order order = orderService.createOrder(userId, productId);order.setId(Long.MAX_VALUE);return order;
}

特点:两个请求访问一个资源(随便选一个creatOrder资源,即加了@SentinelResource的资源),但只限制seckill这个请求

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

流控模式——关联策略:在OrderController加方法,方便测试

@GetMapping("/writeDb")
public String writeDb() {return "writeDb success...";
}
@GetMapping("/readDb")
public String readDb() {log.info("readDb success...");return "readDb success...";
}

在这里插入图片描述

情况有两种

  1. 单独访问/readDb或者/writeDb,多少请求都能成功
  2. /writeDb请求量非常大的时候,突然访问/readDb,则会崩溃,走自定义BlockExceptionHandler的实现类

使用场景:当系统里出现资源竞争的时候,使用关联策略进行限制。例如这里只有写量特别大的时候才会限制读,其他不限制。

注意:这里可能需要手速快点!

5.6.3、流控效果

在这里插入图片描述
流控效果——快速失败

作用:处理不了的请求直接丢弃。交给Web接口异常处理MyBlockExceptionHandler

在这里插入图片描述
在这里插入图片描述

流控效果——Warm Up

作用:慢慢将每秒的请求达到峰值,有个预热机制

例如我这里QPS是10,需要经过3秒才能达到10,前三秒是慢慢将能接收请求数量提上来。

在这里插入图片描述

流控效果——排队等待

在这里插入图片描述
在这里插入图片描述

注意!

在这里插入图片描述

5.7、规则 - 熔断降级

熔断降级是保护自身的手段,通常配置在调用端

5.7.1、断路器

在这里插入图片描述

5.7.2、工作原理

在这里插入图片描述

5.7.3、熔断与兜底

在这里插入图片描述

5.7.4、熔断策略

慢调用比例

举例:统计时长5秒,比例阈值70%的请求在最大RT(最大反应时间)1秒以上,则触发熔断降级。

熔断时长:断开时间,时间到了则会发一个请求试探,有用则通,没用则再继续熔断。

最小请求数:指统计时长内最少发的请求数量。

RT:response time

此处:由于是在远程调用处设置了熔断策略,所以熔断之后走openFeignfallback处理

此处发生熔断后直接回调,不发远程请求

在这里插入图片描述

实验

在这里插入图片描述

异常比例

统计时长内发生异常的比例达到比例阈值,则发生熔断.

此处发生熔断后直接回调,不发远程请求。

在这里插入图片描述
在这里插入图片描述

异常数

统计时长内发生异常的数量达到设置的异常数,则发生熔断.

此处发送了10个远程调用的请求发现都是异常的,直接熔断,30秒内不会再进行远程调用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.8、规则 - 热点参数

在这里插入图片描述

案例

在这里插入图片描述

在这里插入图片描述

@GetMapping("/seckill")
@SentinelResource(value = "seckill-order",fallback = "seckillFallback") //此处用于测试热点规则
//    public Order seckill(@RequestParam("userId") Long userId,
//                         @RequestParam("productId") Long productId) {
//此处模拟不传参数,给默认参数
//    public Order seckill(@RequestParam(value = "userId",defaultValue = "888") Long userId,
//                         @RequestParam(value = "productId",defaultValue = "1000") Long productId) {
public Order seckill(@RequestParam(value = "userId",required = false) Long userId,@RequestParam(value = "productId",required = false) Long productId) {Order order = orderService.createOrder(userId, productId);order.setId(Long.MAX_VALUE);return order;
}public Order seckillFallback(Long userId, Long productId, Throwable exception) {System.out.println("seckillFallback...");Order order = new Order();order.setId(productId);order.setUserId(userId);order.setAddress("seckillFallback异常信息" + exception.getClass());return order;
}

需求一

携带流控参数的参与流控,不携带的不参与。

eg: 带了userId流空规则生效,不带不生效。

参数索引标注了参数位置

在这里插入图片描述

需求二

这里在参数索引位置为0的参数中,设置了参数值=6的特殊情况,它的限流阈值是10000.

意味着,除了userId=6的请求,其他请求还是每秒不能超过1

在这里插入图片描述

需求三

意味着在索引参数为1的参数上,其他请求阈值是100000,但是参数值=666的情况,则限流阈值=0,意味着参数值为666的商品,不让访问。

在这里插入图片描述

为什么这里没走fallback回调?

因为用错了异常,不能用BlockException,应该用Throwable

在这里插入图片描述

六、Gateway - 网关

官网:https://spring.io/projects/spring-cloud-gateway

在这里插入图片描述
在这里插入图片描述

6.1、基础入门

6.1.1、功能

在这里插入图片描述

6.1.2、原理

在这里插入图片描述

6.1.3、环境配置

建module: gateway微服务

在这里插入图片描述

改pom

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency>
</dependencies>

写yml

application.yml

spring:application:name: gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848profiles:include: route
server:port: 80

application-route.yml

先简单测试

spring:cloud:gateway:routes:- id: orderuri: lb://service-orderpredicates:- Path=/api/order/**- id: producturi: lb://service-productpredicates:- Path=/api/product/**

后期完整版

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOriginPatterns: '*'allowedHeaders: '*'allowedMethods: '*'default-filters:- AddResponseHeader=X-Response-Abc,123routes:- id: binguri: https://cn.bing.com/predicates:- name: Pathargs:patterns: /search- name: Queryargs:param: qregexp: haha
#            - Vip=user,lei- name: Vipargs:param: uservalue: leiorder: 10- id: order-routeuri: lb://service-orderpredicates:- name: Pathargs:patterns: /api/order/**matchTrailingSlash: truefilters:- RewritePath=/api/order/?(?<segment>.*), /$\{segment}- OnceToken=X-Response-Token,jwtorder: 1- id: product-routeuri: lb://service-productpredicates:- Path=/api/product/**filters:- RewritePath=/api/product/?(?<segment>.*), /$\{segment}order: 2

启动类

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

业务类

由于配置文件写了路由过滤规则,则需要改

修改OrderController

在这里插入图片描述

修改ProductFeignClient

在这里插入图片描述

修改ProductController

在这里插入图片描述

测试

在这里插入图片描述

6.2、Predicate - 断言

短写法

这里根据不同服务的predicates条件,将请求执行不同服务的uri

order:代表predicates执行顺序,越小越优先

spring:cloud:gateway:routes:- id: orderuri: lb://service-orderpredicates:- Path=/api/order/**- id: producturi: lb://service-productpredicates:- Path=/api/product/**

长写法

在这里插入图片描述

predicates可选列表

在这里插入图片描述
在这里插入图片描述

参数(个数/类型)作用
After1/datetime在指定时间之后
Before1/datetime在指定时间之前
Between2/datetime在指定时间区间内
Cookie2/string,regexp包含cookie名且必须匹配指定值
Header2/string,regexp包含请求头且必须匹配指定值
HostN/string请求host必须是指定枚举值
MethodN/string请求方式必须是指定枚举值
Path2/List<String>,bool请求路径满足规则,是否匹配最后的/
Query2/string,regexp包含指定请求参数
RemoteAddr1/List<String>请求来源于指定网络域(CIDR写法)
Weight2/string,int按指定权重负载均衡
XForwardedRemoteAddr1/List<string>从X-Forwarded-For请求头中解析请求来源,并判断是否来源于指定网络域

自定义predicates 根据QueryRoutePredicateFactory仿写

@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {public VipRoutePredicateFactory() {super(Config.class);}//段格式传参顺序@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("param", "value");}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {// localhost/search?q=haha&user=leifengyangServerHttpRequest request = serverWebExchange.getRequest();String first = request.getQueryParams().getFirst(config.param);return StringUtils.hasText(first) && first.equals(config.value);}};}@Validatedpublic static class Config {@NotEmptyprivate String param;@NotEmptyprivate String value;public @NotEmpty String getParam() {return param;}public void setParam(@NotEmpty String param) {this.param = param;}public @NotEmpty String getValue() {return value;}public void setValue(@NotEmpty String value) {this.value = value;}}
}

在这里插入图片描述

6.3、Filter - 过滤器

写法

也有长写法和短写法

在这里插入图片描述

- RewritePath=/api/order/?(?<segment>.*), /$\{segment}

这条规则的作用是:将路径 /api/order/{任意内容} 重写为 /{任意内容}。换句话说,它去掉了 /api/order/ 前缀,保留了后面的路径部分。

例如:

  • /api/order/123 会被重写为 /123
  • /api/order/abc/xyz 会被重写为 /abc/xyz

这类配置通常用于将请求从一个路径重定向到另一个路径,或者将路径中的某些部分移除。

在此处的作用是不用在各微服务加前缀,这里可以统一管理。

在这里插入图片描述

Filter可选列表

参数(个数/类型)作用
AddRequestHeader2/string添加请求头
AddRequestHeadersIfNotPresent1/List<string>如果没有则添加请求头,key:value方式
AddRequestParameter2/string、string添加请求参数
AddResponseHeader2/string、string添加响应头
CircuitBreaker1/string仅支持forward:/inCaseOfFailureUseThis方式进行熔断
CacheRequestBody1/string缓存请求体
DedupeResponseHeader1/string移除重复响应头,多个用空格分割
FallbackHeaders1/string设置Fallback头
JsonToGrpc请求体Json转为gRPC
LocalResponseCache2/string响应数据本地缓存
MapRequestHeader2/string把某个请求头名字变为另一个名字
ModifyRequestBody仅 Java 代码方式修改请求体
ModifyResponseBody仅 Java 代码方式修改响应体
PrefixPath1/string自动添加请求前缀路径
PreserveHostHeader0保护Host头
RedirectTo3/string重定向到指定位置
RemoveJsonAttributesResponseBody1/string移除响应体中的某些Json字段,多个用,分割
RemoveRequestHeader1/string移除请求头
RemoveRequestParameter1/string移除请求参数
RemoveResponseHeader1/string移除响应头
RequestHeaderSize2/string设置请求大小,超出则响应431状态码
RequestRateLimiter1/string请求限流
RewriteLocationResponseHeader4/string重写Location响应头
RewritePath2/string路径重写
RewriteRequestParameter2/string请求参数重写
RewriteResponseHeader3/string响应头重写
SaveSession0session保存,配合spring-session框架
SecureHeaders0安全头设置
SetPath1/string路径修改
SetRequestHeader2/string请求头修改
SetResponseHeader2/string响应头修改
SetStatus1/int设置响应状态码
StripPrefix1/int路径层级拆除
Retry7/string请求重试设置
RequestSize1/string请求大小限定
SetRequestHostHeader1/string设置Host请求头
TokenRelay1/stringOAuth2的token转发

自定义Filter

@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return chain.filter(exchange).then(Mono.fromRunnable(()->{//注意这里是responseServerHttpResponse response = exchange.getResponse();HttpHeaders headers = response.getHeaders();String value = config.getValue();if ("uuid".equalsIgnoreCase(value)) {value = UUID.randomUUID().toString();}if ("jwt".equalsIgnoreCase(value)) {value = "JWT";}headers.add(config.getName(), value);}));}};}
}

在这里插入图片描述

测试:

在这里插入图片描述

设置默认filter

在这里插入图片描述

6.4、CORS - 跨域处理

全局跨域

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOrigins: "https://docs.spring.io"allowedMethods:- GET
  • 适用于所有路径([/**]
  • 允许任何来源(allowedOriginPatterns: '*') 访问 API
  • 允许所有 HTTP 头部(allowedHeaders: '*'
  • 允许所有请求方法(allowedMethods: '*'),包括 GET、POST、PUT、DELETE 等。

[/**] 其中 /** 代表所有 API 路径

注意:[/**]必须加方括号 [],否则 YAML 解析可能会出错。

测试

在这里插入图片描述

局部跨域

spring:cloud:gateway:routes:- id: cors_routeuri: https://example.orgpredicates:- Path=/service/**metadata:cors:allowedOrigins: '*'allowedMethods:- GET- POSTallowedHeaders: '*'maxAge: 30

6.5、GlobalFilter

/*
* 此实例作用:GlobalFilter 通常,全局过滤器在网关层 用于 拦截所有请求,
* 而局部过滤器(GatewayFilter)用于 单个路由。
* 案例:请求耗时=请求结束时间-请求进来时间
* */
@Component
@Slf4j
public class RTGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String uri = request.getURI().toString();long startTime = System.currentTimeMillis();log.info("请求【{}】开始,时间{}", uri, startTime);//=============上面是前置逻辑==================Mono<Void> filter = chain.filter(exchange).doFinally(r -> {long endTime = System.currentTimeMillis();log.info("请求【{}】结束,时间{},耗时:{}ms", uri, endTime, endTime - startTime);});return filter;}@Overridepublic int getOrder() {return 0;}
}

测试

在这里插入图片描述


参考链接:
https://blog.csdn.net/weixin_56884174/article/details/145573890
https://www.yuque.com/leifengyang/sutong/oz4gbyh5maa0rmxu#tHTwd

相关文章:

  • Scrapy结合Selenium实现搜索点击爬虫的最佳实践
  • 一站式Windows下Docker开启MySQL并链接本地Navicat(附乱码解决方案)
  • Docker学习笔记-docker安装、删除
  • 单片机任意普通IO引脚使用定时器扩展外部中断的巧妙方法
  • 如何撤回刚提交的 commit
  • 在交换机上划分VLAN并配置IP地址的完整指南
  • C数据结构--顺序表
  • 【Linux】41.网络基础(2.3)
  • SQL 查询中 ORDER BY 的执行顺序
  • 30学Java第十天——类加载的过程
  • **searchProperties 是什么,python中**是什么:解包字典的操作符
  • camx的xml解析
  • 【跳坑日记】Jetson 6.2 编译cuda-sample报错:No CMAKE_CUDA_COMPILER could be found
  • java android持久化数据
  • c#内存泄露的原因和解决办法
  • 全新电脑如何快速安装nvm,npm,pnpm
  • 批量将文件夹名称、文件夹路径提取到 Excel 清单
  • git在IDEA中使用技巧
  • RabbitMQ消息的可靠性
  • 腾讯云golang一面
  • 法院就“行人相撞案”道歉:执法公正,普法莫拉开“距离”
  • 中美会谈前都发生了什么?美方为何坐不住了?
  • 长期对组织隐瞒真实年龄,广元市城发集团原董事韩治成被双开
  • 聆听百年唐调正声:唐文治王蘧常吟诵传习的背后
  • 国家出口管制工作协调机制办公室部署开展打击战略矿产走私出口专项行动
  • 玉渊谭天丨一艘航母看中国稀土出口管制为何有效