网关过滤工厂
在上一篇文章中,主要是对网关进行了一个总体的介绍,然后对网关中的断言进行了一个描述。在这篇文章中,主要是对网关中的最后一大核心——过滤进行介绍。
当客户端发送过来的请求经过断言之后,如果还想在请求前后添加一些逻辑,那么就可以使用过滤器来做。这个过滤器其实就相当于SpringMVC中的拦截器、Servlet中的过滤器。同样,过滤和断言类似,SpringCloudGateway内部也内置了许多Filter。
过滤器可以分为全局默认过滤器(GlobalFilter)、单一内置过滤器(GatewayFilter)以及自定义过滤器。
过滤器可以在请求前后对业务逻辑进行处理,因此它的功能有:请求鉴权、记录接口耗时等。
GatewayFilter
GatewayFilter,表示单一内置过滤器,一般应用到单个路由或者一个分组的路由上。
和断言相同,在网关服务的配置文件中配置条件,然后在订单服务创建一个FilterController类来测试项目。
跟请求头相关的
AddRequestHeaderGatewayFilterFactory
该过滤器表示在请求头上添加内容,具体内容跟自己配置的文件相关。
如下配置表示在/filter/addRequestHeader请求的请求头上加上key为role,value为admin的内容。
spring:
cloud:
gateway:
routes:
- id: 11
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/addRequestHeader
filters:
- AddRequestHeader=role, admin
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* AddRequestHeaderGatewayFilterFactory
* 表示在请求头中添加一些内容
* 测试添加的是role=admin
*/
@GetMapping("/addRequestHeader")
public String addRequestHeader() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
String role = request.getHeader("role");
return "在过滤内置工厂中添加的内容为:role = " + role;
}
}
RemoveRequestHeaderGatewayFilterFactory
改过滤器表示将请求头上的内容删除,具体删除内容跟配置文件有关。
如下配置表示移除请求头中key为content的内容。在postman的请求中,专门加入要移除的内容,测试之后发现请求头中确实没有,表示验证成功。
spring:
cloud:
gateway:
routes:
- id: 12
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/removeRequestHeader
filters:
- RemoveRequestHeader=content
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* RemoveRequestHeaderGatewayFilterFactory
* 表示移除请求头中的一些内容
* 测试移除的是content
*/
@GetMapping("/removeRequestHeader")
public String removeRequestHeader(HttpServletRequest request) {
String value = "";
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerKey = headers.nextElement();
String headValue = request.getHeader(headerKey);
value = value + headerKey + '\t' + headValue + '\n';
}
return value;
}
}
SetRequestHeaderGatewayFilterFactory
该过滤器表示修改请求头原先的一些设置,测试发现好像即使没加这个请求头,他也会自动加上。
如下配置表示将请求头中key为usernmae的内容,将其value设置成wbz。
spring:
cloud:
gateway:
routes:
- id: 13
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/setRequestHeader
filters:
- SetRequestHeader=username, wbz
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* SetRequestHeaderGatewayFilterFactory
* 表示将原先请求头中的内容进行更换
* 测试是将key为username的wky更换成wbz
*/
@GetMapping("/setRequestHeader")
public String setRequestHeader(HttpServletRequest request) {
return "请求头中username对应的是:" + request.getHeader("username");
}
}
跟请求参数相关的
AddRequestParameterGatewayFilterFactory
该过滤器表示在请求参数上添加一些内容。
如下配置表示在请求参数上添加key为phone,value为13191038888的内容。
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* AddRequestParameterGatewayFilterFactory
* 表示在请求参数中加入一些内容
* 测试是加入一个key为phone,value为1319103888的键值对
*/
@GetMapping("/addRequestParameter")
public String addRequestParameter(HttpServletRequest request, String phone) {
log.info("测试" + phone);
return "phone:" + request.getParameter("phone");
}
}
spring:
cloud:
gateway:
routes:
- id: 14
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/addRequestParameter
filters:
- AddRequestParameter=phone,13191038888
RemoveRequestParameterGatewayFilterFactory
该过滤器表示删除请求参数上的一些内容。
如下配置表示删除请求参数上key为nickName的内容。
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* RemoveRequestParameterGatewayFilterFactory
* 表示在请求参数中删除一些内容
* 测试是删除一个key为nickName,无论value是啥的内容
*/
@GetMapping("removeRequestParameter")
public String removeRequestParameter(HttpServletRequest request) {
return "nickName:" + request.getParameter("nickName");
}
}
spring:
cloud:
gateway:
routes:
- id: 15
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/removeRequestParameter
filters:
- RemoveRequestParameter=nickName
跟响应头相关的
AddResponseHeaderFilterGatewayFactory
该过滤器表示在响应头上添加一些内容。
如下配置表示在响应头上新增一个key为role,value为admin的键值对。
spring:
cloud:
gateway:
routes:
- id: 16
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/addResponseHeader
filters:
- AddResponseHeader=role, admin
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* AddResponseHeaderGatewayFilterFactory
* 表示在响应头中新增一些内容
* 测试是新增一个key为role,content为admin的键值对
*/
@GetMapping("/addResponseHeader")
public String addResponseHeader(HttpServletResponse response) {
return "响应";
}
}
RemoveResponseHeaderFilterGatewayFactory
该过滤器表示移除响应头上的一些内容。
如下配置表示将响应头中key为content的内容移除
spring:
cloud:
gateway:
routes:
- id: 17
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/removeResponseHeader
filters:
- RemoveResponseHeader=content
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* RemoveResponseHeaderGatewayFilterFactory
* 表示在响应头中移除一些内容
* 测试是将key为content的内容移除
*/
@GetMapping("/removeResponseHeader")
public String removeResponseHeader(HttpServletResponse response) {
response.setHeader("content", "delete");
return "响应";
}
}
SetResponseHeaderFilterGatewayFactory
该过滤器表示设置响应头上的一些内容,即使原本响应头上没有,依旧可以设置成功,有的话就换成设置之后的。
如下配置表示将key为username的对应的value设置成wbz。
spring:
cloud:
gateway:
routes:
- id: 18
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/setResponseHeader
filters:
- SetResponseHeader=username, wbz
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* SetResponseHeaderGatewayFilterFactory
* 表示在响应头中设置一些内容
* 测试是将key为username的对应value设置为wbz
*/
@GetMapping("/setResponseHeader")
public String setResponseHeader(HttpServletResponse response) {
response.setHeader("username", "wky");
return "响应";
}
}
跟路径有关的
PrefixPathGatewayFilterFactory
该过滤器是用来设置统一前缀的,假设某个服务的路径都带有一个相同的前缀,那么就可以使用该过滤器进行设置。当请求通过断言之后,过滤器路由服务之前就会自动加上前缀。
如下配置请求的完整URL是/filter/prefixPath,我将filter抽取出来放到过滤器中,因此我在输入URL时,只输入127.0.0.1:9527/prefixPath,就可以成功路由到/filter/prefixPath上。
spring:
cloud:
gateway:
routes:
- id: 19
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/prefixPath
filters:
- PrefixPath=/filter
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* PrefixPathGatewayFilterFactory
* 表示设置一个响应统一前缀
*/
@GetMapping("/prefixPath")
public String prefixPath() {
return "设置统一前缀成功";
}
}
SetPathGatewayFilterFactory
该过滤器是用来进行地址替换的,客户端发送的地址经过断言之后,就会替换成过滤器中给出的真实地址。
如下配置是客户端发送的请求地址是127.0.0.1:9527/random/test,断言判断为true之后,过滤器就会将这个地址进行替换,然后再向服务端发送请求。
spring:
cloud:
gateway:
routes:
- id: 20
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/random/{regexp}
filters:
- SetPath=/filter/setPath/{regexp}
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* SetPathGatewayFilterFactory
* 地址替换,即客户端发送的请求是根据断言来的
* 断言成功之后过滤器会将其替换成真实的地址
*/
@GetMapping("/setPath/{regexp}")
public String setPath(@PathVariable String regexp) {
return "地址替换成功";
}
}
RedirectToGatewayFilterFactory
该过滤器表示重定向。
如下配置表示当客户端访问127.0.0.1:9527/redirectTo时,网关就会重定向到百度。
spring:
cloud:
gateway:
routes:
- id: 21
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/redirectTo
filters:
- RedirectTo=302,https://www.baidu.com
其他
RequestRateLimiterGatewayFilterFactory
该过滤器表示为当前网关的所有请求执行限流过滤,如果被限流,默认会响应HTTP 429-Too ManyRequests。默认提供了RedisRateLimiter的限流算法,采用令牌桶算法实现限流功能(对于具体的限流算法,在介绍Sentinel或其他限流组件时会详细介绍)。
如下配置表示限流过滤器的内容。
spring:
cloud:
gateway:
routes:
- id: 22
uri:
predicates:
- Path=/filter/**
filters:
- RequestRateLimiter=redis-rate-limiter.replenishRate, 10
# 令牌填充速度,即每秒钟允许多少个请求(不丢弃任何请求)
- RequestRateLimiter=redis-rate-limiter.burstCapacity, 20
# 令牌桶容量,即每秒⽤⼾最⼤能够执⾏的请求数量(不丢弃任何请求)。将此值设置为零将阻⽌所有请求。
- RequestRateLimiter=redis-rate-limiter.requestedTokens, 1
# 每次请求占⽤⼏个令牌,默认为1。
RetryGatewayFilterFactory
该过滤器表示重试过滤器,会针对不同的响应进行重试。当后端服务不可用时,网关会根据配置参数来发起重试。
如下配置中,设置重试3次,然后针对BAD_GATEWAY的响应进行重试。BAD_GATEWAY是HttpStatus中的状态码,只要配置文件中配置的状态和服务响应回去的状态相同,那么就会进行重试。从结果可以看出,共发送了三次请求,正常发送依次,重试三次。
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* RetryGatewayFilterFactory
* 重试过滤器
*/
@GetMapping("/retry")
public String retry(HttpServletResponse response) {
log.info("重试机制");
response.setStatus(502);
return "重试机制";
}
}
spring:
cloud:
gateway:
routes:
- id: 23
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/retry
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
RequestSizeGatewayFilterFactory
该过滤器表示设置允许接收最大请求包的大小,如果请求大小超过设置的值,则返回413 Payload Too Large。请求包默认大小为5M,单位是字节。
spring:
cloud:
gateway:
routes:
- id: 24
uri: lb://cloud-consumer-order-open-feign-84
predicates:
- Path=/filter/requestSize
filters:
- name: RequestSize
args:
maxSize: 2048
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
/**
* RequestSizeGatewayFilterFactory
* 该过滤器表示能接收的请求包的大小,默认是5MB
*/
@PostMapping("/requestSize")
public String requestSize(@RequestPart MultipartFile file) {
return "文件大小为:" + file.getSize();
}
}
DefaultGatewayFilterFactory
前面写的都是针对某一路由生效的,若需要对全部路由生效,则可以使用该过滤器,这个过滤器就需要一个过滤列表,例如上述的重试过滤器、限流过滤器等等,就可以加入1到默认过滤器中,这样就可以对所有服务生效。
spring:
cloud:
gateway:
default-filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
- name: RequestSize
args:
maxSize: 2048