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

微服务之网关(Spring Cloud Gateway)

微服务学习顺序:
微服务之Nacos
微服务之OpenFeign
微服务之网关

什么是网关

在这里插入图片描述
微服务架构下,分散的服务需要一个 “统一管理者”,来解决外部请求对接、服务治理等共性问题,避免每个服务重复开发相同功能,同时提升系统的安全性、可维护性和稳定性。

  1. 解决 “多服务入口混乱” 问题
    微服务架构中,系统被拆分为多个独立服务(如用户服务、订单服务、商品服务),每个服务都有自己的地址和端口。如果没有网关,外部客户端(APP、网页)需要记住所有服务的地址,分别调用,不仅逻辑复杂,还会增加客户端的维护成本。网关提供统一入口,客户端只需访问一个地址,由网关负责转发请求,简化了调用流程。
  2. 避免 “重复开发共性功能”
    权限认证、日志记录、限流、跨域处理等功能,是所有服务都需要的共性需求。如果没有网关,每个服务都要单独开发这些功能,不仅导致代码冗余、开发效率低,还可能出现实现不统一的问题(如不同服务的认证逻辑不一致)。网关在入口层统一实现这些功能,所有服务直接复用,减少重复工作量。
  3. 提升 “系统安全性与可控性”
    外部请求直接访问后端服务存在安全风险(如恶意请求直接冲击核心服务)。网关作为 “屏障”,可以统一拦截非法请求(如未登录、Token 无效的请求)、过滤危险参数,还能隐藏后端服务的真实地址,降低服务暴露风险。同时,通过网关的监控和限流功能,可实时掌控流量情况,避免高并发压垮后端服务。
  4. 适配 “复杂的架构需求”
    微服务架构中常涉及灰度发布、服务熔断、协议转换等场景。网关可直接集成这些能力:比如灰度发布时,通过网关将部分请求转发到新版本服务;后端服务故障时,网关触发熔断返回兜底响应;外部客户端使用的协议(如 HTTP)与后端服务协议(如 RPC)不匹配时,网关负责协议转换,实现兼容。

简单说,网关就是微服务的 “统一入口”,既帮客户端简化了调用,又帮后端服务解决了共性问题,是微服务架构中不可或缺的中间层。
在这里插入图片描述

GeteWay能做什么

首先要知道网关也是一个java项目

  • 反向代理
  • 鉴权(可用过滤器来做)
  • 流量控制
  • 熔断降级
  • 日志监控
    在这里插入图片描述

核心概念

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

Predicate(断言):断言说简单点,就是请求匹配条件。断言是定义匹配条件,如果请求符合条件,则该请求匹配断言所属的路由。

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

Gateway搭建

这里项目是在我的另一篇文章中的项目基础上进行创建:微服务之OpenFeign

在父级项目cloud-alibaba-test下创建springboot项目cloud-gateway-8080
在这里插入图片描述
勾选Spring Web、Gateway
在这里插入图片描述
删除默认生成的demos.web目录
在这里插入图片描述

配置pom文件,引入依赖

<!--引入父工程cloud-alibaba-test,并指定要打成jar包-->
<!--指定父级-->
<parent><groupId>com.example</groupId><artifactId>cloud-alibaba-test</artifactId><version>0.0.1-SNAPSHOT</version>
</parent>
<!--指定打包方式-->
<packaging>jar</packaging><!--网关需要使用webflux,这里需要把web依赖替换为换成webflux依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency><!--网关依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

nacos注册中心(nacos-discovery)和loadbalancer(使用OpenFeign时需要)已经在父工程cloud-alibaba-test引过了,子项目可以调用,这里就不需要再引入了。

Spring Cloud Gateway是基于webflux的,如果非要web支持的话需要导入spring-boot-starter-webflux而不是spring-boot-start-web。

在父级项目引入项目cloud-gateway-8080

<!--指定子模块-->
<modules><module>bill-7780</module><module>bill-7781</module><module>provider-7790</module><module>cloud-common</module><module>cloud-gateway-8080</module>
</modules>

启动类添加注解@EnableDiscoveryClient,开启nacos服务注册与发现

package com.lp;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication
public class CloudGateway8080Application {public static void main(String[] args) {SpringApplication.run(CloudGateway8080Application.class, args);}}

自动路由

编写application.yml

server:port: 8080
spring:application:name: cloud-gateway-8080 # 服务名称cloud:nacos:discovery:server-addr: 127.0.0.1:8850 # nacos服务地址,注册服务username: nacospassword: nacosgateway:discovery:locator:enabled: true #开启gateway自动发现所处nacos注册中心的所有服务的功能,并为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务。lower-case-service-id: true # 服务名转为小写(如服务名是BILL-7780,请求时用/bill-7780/控制器方法访问路径 即可匹配)

网关会自动捕捉放到注册中心的服务,然后生成一个访问路径

启动项目bill-7780、provider-7790、cloud-gateway-8080,注册到nacos服务
在这里插入图片描述

浏览器输入路径 本机ip:gateway端口号/要请求的服务名/控制器方法访问路径,如:http://localhost:8080/bill-7780/bill/list
在这里插入图片描述
测试成功!!!!

注意:有些版本无法使用,权限不足,需要配置自定义路由。

自定义路由

修改yml文件信息

server:port: 8080
spring:application:name: cloud-gateway-8080 # 服务名称cloud:nacos:discovery:server-addr: 127.0.0.1:8850 # nacos服务地址,注册服务username: nacospassword: nacosgateway:discovery:locator:enabled: false #开启gateway自动发现所处nacos注册中心的所有服务的功能,并为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务。lower-case-service-id: true # 服务名转为小写(如服务名是BILL-7780,请求时用 /bill-7780/控制器方法访问路径 即可匹配)routes:- id: bill-7780 # 可以随便写,但一般都是服务名,且要唯一uri: lb://bill-7780 #lb(loadbalancer负载均衡)://服务名。如果没有loadbalancer,就只能使用http://服务IP:端口号predicates: # 断言(判断请求是否符合当前路由的条件)- Path=/billApi/** #当请求路径以/billApi开头时,触发当前路由。到此访问路径应为127.0.0.1:8080/billApi/bill/list,但我的controller中没有/billApi访问路径,会访问失败,这里只是演示,配合下面的filters才能访问成功filters: # 过滤器(对请求/响应进行处理)- StripPrefix=1 # 去掉请求路径中的第一个路径参数,即去掉/billApi。此时访问路径为127.0.0.1:8080/billApi/bill/list。网关将处理后的/bill/list转发到bill-7780服务,与后端接口路径完全匹配,因此可以正常访问- id: provider-7790uri: lb://provider-7790predicates:- Path=/providerApi/**filters:- StripPrefix=1
  • 注意yml格式,尤其是空格。
  • 关闭gateway开启服务注册和发现的功能(enabale: false),也可以删去enabale: false,否则自定义不生效。
  • routes 后面的路由可以配置多个,相当于配置一个数组,一个-开头的配置就是其中的一个数组元素。

路由主要有四个配置:

  1. 路由id(id),可以随便写,但一般都是服务名。
  2. 路由目标(uri),目标服务地址(转发的终点)
    uri 定义了请求最终要转发到的服务地址,决定了 “转发到哪里”,常见格式有两种:
    • 负载均衡模式(推荐,适用于微服务。通过服务名来访问,不用担心服务ip变动问题)
      格式:lb://服务名(lb 代表启用负载均衡)
      • 规则:网关会从服务注册中心(如 Nacos)获取 bill-7780 服务的所有实例(IP + 端口),自动通过负载均衡选择一个实例转发请求。
      • 注意:服务名必须与注册中心中注册的服务名完全一致(区分大小写,除非配置了 lower-case-service-id: true 转为小写)。
    • 固定地址模式(通过ip访问,若ip变动,就访问不到了。适用于非注册中心的服务)
      格式:http://服务IP:端口https://服务IP:端口
      • 规则:直接将请求转发到指定的 IP 和端口,不经过服务发现和负载均衡。
  3. 路由断言(predicates):路径匹配规则(触发转发的条件)
    • predicates 是一组 “断言条件”,只有当客户端请求满足条件时,才会命中当前路由并转发。最常用的是 Path 断言(路径匹配),比如Path=/billApi,则请求路径必须/billApi开头。
  4. 路由过滤器(filters):路径处理规则(转发前的路径转换
    • StripPrefix=n:移除路径的前 n 层前缀
      :filters: - StripPrefix=1,配合 predicates: Path=/billApi/**
      客户端请求路径:/billApi/bill/list。
      处理后路径:/bill/list(移除第 1 层前缀 /billApi)。
      最终转发到目标服务的路径:/bill/list。
      • 规则:n 表示要移除的前缀层数(以 / 分隔为一层),如 /a/b/c 中,a 是第 1 层,b 是第 2 层。
    • PrefixPath=/前缀:给路径添加前缀
    • 核心规则:
      过滤器仅修改 “转发到后端服务的路径”,不影响客户端请求网关的原始路径。
      多个过滤器可以组合使用,按配置顺序执行。

自定义路由模式下,访问路径与服务名完全无关。客户端只需按照网关 predicates 中定义的路径规则访问即可,无需知道后端服务的真实名称(如 bill-7780),服务名仅作为网关内部转发时定位目标服务的标识。

注意:当两个自定义路由的 Path 断言值完全相同时(例如均为 /billApi/**),网关会按yml配置文件中 routes 列表的书写顺序依次匹配路由,会导致请求只会匹配第一个路由,第二个路由永远不会被触发。

重启cloud-gateway-8080项目,注册到nacos服务。
在这里插入图片描述
浏览器访问路径:本机ip+gateway端口号/billApi/controller方法访问路径
在这里插入图片描述
在这里插入图片描述

自动路由VS自定义路由

路由模式访问路径是否包含服务名服务名的作用范围
自定义路由不包含仅网关内部用于定位服务(uri 中)
自动路由包含(作为路径前缀)客户端必须知道服务名才能访问

路由过滤器

在这里插入图片描述
客户端请求先找到路由,路由匹配时经过过滤器层层筛选,最终访问到微服务。

请求头过滤器配置示例(局部过滤器)

filters: # 过滤器配置- AddRequestHeader=name,张三# 添加请求头

在这里插入图片描述
给所有进入bill-7780的请求添加一个请求头。
请求头的key为name,value为123456。
在这里插入图片描述
重启cloud-gateway-8080、bill-7780项目,浏览器访问http://localhost:8080/billApi/bill/list,查看控制台
在这里插入图片描述

默认过滤器配置示例(全局过滤器)

在这里插入图片描述
default-filters 的配置和routes平级。
只要配置在 default-filters 下面的过滤器,会对routes配置的所有路由都生效。
在这里插入图片描述
重启cloud-gateway-8080、bill-7780项目,浏览器访问http://localhost:8080/billApi/bill/list,查看控制台
在这里插入图片描述

自定义全局路由过滤器

有时候SpringCloudGateWay提供的过滤器工厂不能满足自己的要求。

可能有时候需要在过滤时做一些其它的逻辑操作,比如过滤的请求中的一些参数,我们要在过滤器中验证这些参数是否合法(符合规范),如果合法则放行,否则返回错误信息。

那么这时候可以选择使用java代码自定义全局过滤器。

创建GateWayFilter类 实现接口GlobalFilter,使用@Order注解设置过滤器优先级
在这里插入图片描述

package com.lp.filters;import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Order(1)
@Component
public class GateWayFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//getHeaders().getFirst("lp") 获取的是 HTTP请求头 中的第一个token参数,可用来校验token。//前面在yml文件中在全局过滤器中配置过请求头信息中lp的值为666,这里把它当作token来模拟获取请求头中的tokenString token = exchange.getRequest().getHeaders().getFirst("lp");System.out.println("token==="+token);//1. 获取请求参数//这里的request并不是servlet中的request//返回值是一个多键的map集合、也就是说这个map集合的键可以重复//getQueryParams() 获取的是GET请求路径后通过?拼接的参数MultiValueMap<String, String> map = exchange.getRequest().getQueryParams();//2. 获取id参数String id = map.getFirst("id");System.out.println("id==="+id);//3. 校验。我们这里设置如果id为3则放行if(id.equals("3")){//放行System.out.println("进入放行。。。");return chain.filter(exchange);}//4. 拦截//4.1 禁止访问,设置状态码。当前请求被拦截时,返回的状态码为403,让浏览器不至于显示空白页面exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);//状态码//4.2 结束处理return exchange.getResponse().setComplete();}
}

启动bill-7780、provider-7790、cloud-gateway-8080服务(需要提前启动nacos,单例启动即可)

nacos注册中心
在这里插入图片描述

浏览器访问http://localhost:8080/providerApi/bill/listByProId?id=1,被拦截
在这里插入图片描述
在这里插入图片描述

浏览器访问http://localhost:8080/providerApi/bill/listByProId?id=3,访问成功
在这里插入图片描述
在这里插入图片描述
当有多个过滤器(或者说一条过滤链)时,Order的值决定了过滤器的执行顺序。

实现Ordered接口的方式无法在GateWayFilter中获得token,建议使用注解@Order

数值越小,优先级越高,越先执行。(例如 order=-1 比 order=0 先执行)

在 Spring Cloud Gateway 中,default-filters(YAML 配置的全局过滤器)和自定义全局过滤器类(实现 GlobalFilter 接口)的优先级,由它们的 order 值 决定,而非 “配置方式”。

  • default-filters 中内置过滤器的默认order:例如内置过滤器AddRequestHeader 的默认 order=1(不同过滤器的默认 order 由 Spring 预先定义)。
  • 自定义全局过滤器的 order:由开发者指定,例如 @Order(1) 或 getOrder() { return 1; }。

无论哪种全局过滤器,后执行的过滤器都能获取前序过滤器设置的请求头、属性等信息(通过 ServerWebExchange 共享)。


Spring Cloud Gateway 中,当两个过滤器的 order 相同时,执行顺序由它们的 注册顺序 决定:

  • default-filters 中的过滤器是 在网关初始化时优先注册 的(属于框架内置配置,加载时机更早)。
  • 自定义全局过滤器是 在 Spring 容器扫描时注册 的(加载时机晚于 default-filters)。

因此,当 order 相同时,default-filters 中的 AddRequestHeader 会先于自定义过滤器注册,进而先执行。
当全局过滤器的 注册顺序相同 且 order 值也相同 时,执行顺序可视为随机(不确定)。

建议:为所有过滤器设置唯一且明确的 order 值,通过 order 数值大小严格控制执行顺序,而非依赖注册顺序。


过滤器间的数据共享机制
所有过滤器通过 ServerWebExchange 对象共享请求上下文(包括请求头、属性等):

  • AddRequestHeader 先执行时,会将指定的请求头(如 lp: 666)添加到 ServerWebExchange 的请求对象中。
  • 而自定义过滤器后执行时,通过 exchange.getRequest().getHeaders() 就能获取到前序过滤器设置的请求头。

设置Order的值有两种方式:

  1. 使用@Order注解(推荐),如上
  2. 实现Ordered接口,并且重写getOrder方法
public class GateWayFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {...return null;}@Overridepublic int getOrder() {return 1;//返回值即为Order值}
}

网关的跨域问题

使用CORS方式。

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

一般都是在网关配置跨域,而与网关在同一个nacos服务注册中心的其它服务(比如项目中的bill-7780、provider-7790等)不需要跨域,网关能直接访问这些服务。

方式一:配置application.yml文件

spring:cloud:gateway:globalcors: # 全局的跨域配置add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题# options请求 就是一种询问服务器是否浏览器可以跨域的请求# 如果每次跨域都有询问服务器是否浏览器可以跨域对性能也是损耗# 可以配置本次跨域检测的有效期maxAge# 在maxAge设置的时间范围内,不去询问,统统允许跨域corsConfigurations:'[/**]':allowedOrigins: # 允许哪些网站的跨域请求- "http://localhost:8090"allowedMethods: # 允许的跨域ajax的请求方式- "GET"- "POST"- "DELETE"- "PUT"- "OPTIONS"allowedHeaders: "*" # 允许在请求中携带的头信息allowCredentials: true # 允许在请求中携带cookiemaxAge: 360000 # 本次跨域检测的有效期(单位毫秒)# 有效期内,跨域请求不会一直发option请求去增大服务器压力

方式二:使用编码方式定义配置类

package com.lp.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;@Configuration
public class CorsConfig {private static final String MAX_AGE = "18000L";@Beanpublic WebFilter corsFilter() {return (ServerWebExchange ctx, WebFilterChain chain) -> {ServerHttpRequest request = ctx.getRequest();// 使用SpringMvc自带的跨域检测工具类判断当前请求是否跨域if (!CorsUtils.isCorsRequest(request)) {return chain.filter(ctx);}HttpHeaders requestHeaders = request.getHeaders();// 获取请求头ServerHttpResponse response = ctx.getResponse();// 获取响应对象HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); // 获取请求方式对象HttpHeaders headers = response.getHeaders();// 获取响应头headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,requestHeaders.getOrigin()); // 把请求头中的请求源(协议+ip+端口)添加到响应头中(相当于yml中的allowedOrigins)headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,requestHeaders.getAccessControlRequestHeaders());if (requestMethod != null) {headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,requestMethod.name()); // 允许被响应的方法(GET/POST等,相当于yml中的allowedMethods)}headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");// 允许在请求中携带cookie(相当于yml中的allowCredentials)headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");// 允许在请求中携带的头信息(相当于yml中的allowedHeaders)headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);// 本次跨域检测的有效期(单位毫秒,相当于yml中的maxAge)if (request.getMethod() == HttpMethod.OPTIONS) {// 直接给option请求反回结果response.setStatusCode(HttpStatus.OK);return Mono.empty();}return chain.filter(ctx);// 不是option请求则放行};}
}

在这里插入图片描述

网关限流

网关可以做很多的事情,比如,限流。当我们的系统被频繁的请求(请求量过大)的时候,就有可能将系统压垮。所以为了解决这个问题,需要在每一个微服务中做限流操作,这是很麻烦的。但是如果有了网关,那么就可以在网关系统做限流,因为所有的请求都需要先通过网关系统才能路由到微服务中。
在这里插入图片描述
令牌桶算法是比较常见的限流算法之一,大概描述如下:

  • 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
  • 根据限流大小,设置自动按照一定的速率往桶里添加令牌
  • 桶设置最大的放置令牌数量限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
  • 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
  • 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;

在这里插入图片描述

网关限流代码实现

需求:每个ip地址1秒内只能发送1次请求,多出来的请求返回429错误。

spring cloud gateway 默认使用 redis 的 RateLimter 限流算法来实现。所以我们要使用首先需要在网关服务项目的pom文件中引入redis的依赖

<!--redis 限流-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

定义KeyResolver

  • 可以在启动类添加如下代码, KeyResolver 用于计算某一个类型的限流的KEY也就是说,可以通过KeyResolver 来指定限流的Key。
//定义一个KeyResolver,对IP地址进行限流
@Bean
public KeyResolver ipKeyResolver() {return new KeyResolver() {@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {returnMono.just(exchange.getRequest().getRemoteAddress().getHostName());}};
}
  • 也可以专门创建一个限流配置类(推荐)
    在这里插入图片描述
package com.lp.config;import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;//限流配置类
@Configuration
public class ResolverConfig {//定义一个KeyResolver,对IP地址进行限流@Beanpublic KeyResolver ipKeyResolver() {return new KeyResolver() {@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}};}
}

修改application.yml中配置项,指定限制流量的配置以及 redis 的配置

server:port: 8080
spring:application:name: cloud-gateway-8080 # 服务名称cloud:nacos:discovery:server-addr: 127.0.0.1:8850 # nacos服务地址,注册服务username: nacospassword: nacosgateway:discovery:locator:enabled: false #开启gateway自动发现所处nacos注册中心的所有服务的功能,并为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务。lower-case-service-id: true # 服务名转为小写(如服务名是BILL-7780,请求时用 /bill-7780/控制器方法访问路径 即可匹配)routes:- id: bill-7780 # 可以随便写,但一般都是服务名,且要唯一uri: lb://bill-7780 #lb(loadbalancer负载均衡)://服务名。如果没有loadbalancer,就只能使用http://服务IP:端口号predicates: # 断言(判断请求是否符合当前路由的条件)- Path=/billApi/** #当请求路径以/billApi开头时,触发当前路由。到此访问路径应为127.0.0.1:8080/billApi/bill/list,但我的controller中没有/billApi访问路径,会访问失败,这里只是演示,配合下面的filters才能访问成功filters: # 过滤器(对请求/响应进行处理)- StripPrefix=1 # 去掉请求路径中的第一个路径参数,即去掉/billApi。此时访问路径为127.0.0.1:8080/billApi/bill/list。网关将处理后的/bill/list转发到bill-7780服务,与后端接口路径完全匹配,因此可以正常访问- AddRequestHeader=name,123456 # 添加请求头- id: provider-7790uri: lb://provider-7790predicates:- Path=/providerApi/**filters:- StripPrefix=1# 限制流量配置- name: RequestRateLimiter # 请求限流,不能随便乱写args:key-resolver: "#{@ipKeyResolver}" #用于限流的键的解析器的Bean对象的名字,即前面限流配置类中的方法名(ipKeyResolver)。它使用SpEL表达式根据#{@beanName}从Spring容器中获取Bean对象redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率redis-rate-limiter.burstCapacity: 2 #令牌桶总容量。default-filters: # 全局过滤器- AddRequestHeader=lp,666 # 添加请求头# redis配置redis:host: 127.0.0.1port: 6380password: 123456

在这里插入图片描述
解释:

  • burstCapacity :令牌桶总容量。
  • replenishRate :令牌桶每秒填充平均速率。
  • key-resolver :用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL表达式根据 #{@beanName} 从 Spring 容器中获取 Bean 对象。

最好用高版本的redis,如3.2.1版本。否则可能会报错。

先启动redis,再启动项目cloud-gateway-8080(nacos也要处于启动状态),浏览器访问http://localhost:8080/providerApi/bill/listByProId?id=3
在这里插入图片描述
快速刷新,请求失败就会报错429(因为令牌桶里的令牌不够了,导致请求不通过)
在这里插入图片描述

其他限流规则

参数限流:key-resolver: "#{@parameterKeyResolver}"

@Bean
public KeyResolver parameterKeyResolver()
{return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("id"));
}

URI限流(路径限流):key-resolver: "#{@pathKeyResolver}",限制同一个请求路径在一定时间内只能请求一定次数

@Bean
public KeyResolver pathKeyResolver()
{return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
}
http://www.dtcms.com/a/576964.html

相关文章:

  • ES脚本语言Painless介绍
  • 基于MATLAB的雨流计数法疲劳计算GUI可视化系统
  • WiFi 协议精读:IEEE 802.11-2012,IEEE Std 802.11w™-2009: Protected Management Frames
  • RabbitMQ-Exporter 监控 TLS 加密的 RabbitMQ 集群
  • 重庆佳宇建设集团网站重庆网站自己推广
  • 品牌营销策划网站wordpress 会员开卡消费
  • iOS修改tabbar的背景图
  • 《uni-app跨平台开发完全指南》- 04 - 页面布局与样式基础
  • 【学习笔记更新中】Deeplearning.AI 大语言模型后训练:微调与强化学习导论
  • SQL之表的时间类内置函数详解
  • 线性代数 - 奇异值分解(SVD Singular Value Decomposition)- 计算顺序 旋转→拉伸→旋转
  • html的input的required
  • 【开题答辩全过程】以 基于Java的医务室病历管理小程序为例,包含答辩的问题和答案
  • 移除 XSLT,以更强的浏览器安全边界迎面而来
  • 回溯剪枝的“减法艺术”:化解超时危机的 “救命稻草”(三)
  • 佛山网站建设设计公司陕西住建执业证书官网
  • Rust编程学习 - 自动解引用的用处,如何进行“解引用”(Deref) 是“取引用”(Ref) 的反操作
  • 云计算产品-介绍--网络/CDN篇
  • 云计算产品-介绍--安全篇
  • 3D模型骨骼绑定与动画完全指南-web平台
  • RabbitMQ 是否也支持消费组
  • 德国域名申请网站网站建设 推广薪资
  • 从零开始搭建 flask 博客实验(常见疑问)
  • 给予虚拟成像台尝鲜版十,完善支持HTML原型模式
  • ⸢ 拾叁-Ⅰ⸥⤳ 安全水位评估框架(上):威胁路径模型
  • 【Python Web开源框架】Django/Flask/FastAPI/Tornado/Pyramid
  • 拼多多seo搜索优化西安网站seo技术
  • DocxFactory: 一个C++操作word的开源库(不依赖office控件)
  • layui框架中,表单元素不显示问题
  • 主流模型调用