1、FallbackHeaders GatewayFilter
FallbackHeaders允许在触发熔断转发到外部应用程序中的fallbackUri的请求的标头中添加Spring Cloud CircuitBreaker执行异常详细信息。例如:
spring:
cloud:
gateway:
enabled: true
routes:
- id: Goods-Server # 路由 id,唯一标识
uri: lb://producer
predicates:
# - Path=/** # 断言,路由匹配条件,匹配 /product 开头的所有 api
- Path=/producer/{segment}
filters:
- StripPrefix=1
- AddRequestHeader=X-Request-red, Blue-{segment}
- AddRequestParameter=red, bar-{segment}
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/myfallback
statusCodes:
- 500
- "NOT_FOUND"
- id: ingredients-fallback
uri: http://localhost:8002/
predicates:
- Path=/myfallback
filters:
- name: FallbackHeaders
args:
rootCauseExceptionMessageHeaderName: Test-Header
8002是Producer服务的端口。触发熔断时会将请求转发到Producer的/myfallback。先注释gatewayServer里面的Fallback Controller,确保降级回调到Producer的/myfallback.
修改Producer服务:
@RequestMapping("/hello")
public String hello(String name, HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getHeader("x-request-red"));
System.out.println(request.getParameter("red"));
int i = 10 / 0;
return "hello," + name + "," + port;
}
确保调用服务引发异常。
在Producer模块增加服务降级回调:
@RestController
public class FallbackController {
private String dateStr(){
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
}
/**
* 返回字符串类型
* @return
*/
@GetMapping("/myfallback")
public String helloStr(HttpServletRequest request) {
String s= request.getHeader("Test-Header");
System.out.println("producer:"+s);
return "producer myfallback, " + dateStr();
}
}
访问http://localhost:8500/producer/hello,查看Producer控制台,发现:
如果将FallbackController移到gatewayServer模块,则服务降级回调/myfallback获取不到请求头。
还可以通过设置以下参数的值(以默认值显示)来覆盖配置中标头的名称:
- executionExceptionTypeHeaderName ("Execution-Exception-Type")
- executionExceptionMessageHeaderName ("Execution-Exception-Message")
- rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
- rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")
2、MapRequestHeader GatewayFilter
MapRequestHeader GatewayFilter采用fromHeader和toHeader参数。它创建一个新的命名标头(toHeader),并从传入的http请求中的现有命名标头(fromHeader)中提取值。如果输入标头不存在,则过滤器没有影响。如果新的命名标头已经存在,则其值将使用新值进行扩充。例如:
spring:
cloud:
gateway:
enabled: true
routes:
- id: Goods-Server # 路由 id,唯一标识
uri: lb://producer
predicates:
# - Path=/** # 断言,路由匹配条件,匹配 /product 开头的所有 api
- Path=/producer/{segment}
filters:
- StripPrefix=1
- MapRequestHeader=X-Request-Red, Blue
Producer服务的Controller:
@RequestMapping("/hello")
public String hello(String name, HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getHeader("X-Request-Red"));
System.out.println(request.getHeader("blue"));
return "hello," + name + "," + port;
}
用Postman调用http://localhost:8500/producer/hello:
查看Producer控制台:
3、PrefixPath GatewayFilter
PrefixPath GatewayFilter将在匹配的请求前面加上前缀。例如:
spring:
cloud:
gateway:
enabled: true
routes:
- id: Goods-Server # 路由 id,唯一标识
uri: lb://producer
predicates:
# - Path=/** # 断言,路由匹配条件,匹配 /product 开头的所有 api
- Path=/producer/{segment}
filters:
- StripPrefix=1
- PrefixPath=/mypath
比如请求路径是/producer/hello,StripPrefix会移除/producer,PrefixPath会加前缀,所以请求路径是/mypath/hello。访问http://localhost:8500/producer/hello报404。Producer服务的请求路径从:
@RequestMapping("/hello")
public String hello(String name, HttpServletRequest request, HttpServletResponse response) {
return "hello," + name + "," + port;
}
修改为:
@RequestMapping("/mypath/hello")
public String hello(String name, HttpServletRequest request, HttpServletResponse response) {
return "hello," + name + "," + port;
}
访问http://localhost:8500/producer/hello,成功。
4、PreserveHostHeader GatewayFilter
PreserveHostHeader GatewayFilter没有参数。此筛选器设置一个请求属性,路由过滤器检查该属性以确定是否应发送原始主机标头,而不是HTTP客户端确定的主机标头。
spring:
cloud:
gateway:
enabled: true
routes:
- id: Goods-Server # 路由 id,唯一标识
uri: lb://producer
predicates:
# - Path=/** # 断言,路由匹配条件,匹配 /product 开头的所有 api
- Path=/producer/{segment}
filters:
- StripPrefix=1
- PreserveHostHeader
5、RequestRateLimiter GatewayFilter
RequestRateLimiter GatewayFilter是限速过滤器。如果被限速会返回HTTP 429 - Too Many Requests。使用Redis来限流。所使用的算法是令牌桶算法。
spring:
cloud:
gateway:
enabled: true
routes:
- id: Goods-Server # 路由 id,唯一标识
uri: lb://producer
predicates:
# - Path=/** # 断言,路由匹配条件,匹配 /product 开头的所有 api
- Path=/producer/{segment}
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 20
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
key-resolver: "#{@keyResolver}"
redis:
host: localhost
port: 6379
replenishRate是希望用户在不丢弃任何请求的情况下每秒可以执行的请求数。这是填充令牌桶的速率。
burstCapacity是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为零将阻止所有请求。
requestedTokens是一个请求花费的令牌数。这是针对每个请求从存储桶中获取的令牌数量,默认为1。
KeyResolver接口允许可插入策略用于限制请求的密钥。#{@keyResolver}里面的keyResolver是Bean的名字。
在GatewayServer添加依赖并配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>3.0.6</version>
</dependency>
@Configuration
public class MyConfig {
@Bean("keyResolver")
public KeyResolver pathKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
}
}
使用jmeter来测试限流:
添加线程组:
设置线程数,循环次数:
添加http请求:
配置ip,端口,url等:
添加汇总报告:
点击执行后查看汇总报告: