SpringCloud Gateway内置过滤器
基于2.2.4Release。Spring Cloud Gateway
SpringCloud Gateway的filter从作用范围上分有两种
- 针对于单个路由的gateway filter,它在配置文件中的写法同predict类似
- 针对于所有路由的global filer。不需要在配置文件中配置,即对所有路由生效。
GatewayFilter
为了方便起见,springcloud已经内置了很多常用的过滤器,我们应该知晓这些官方过滤器的存在,避免重复造轮子。具体每个过滤器的用法细节用到时再细究。
| 过滤器名 | 作用 | |
|---|---|---|
| AddRequestHeader | 为原始请求添加Header | |
| AddRequestParameter | 为原始请求添加请求参数 | |
| AddResponseHeader | 为原始响应添加Header | |
| DedupeResponseHeader | 剔除响应头中重复的值 | |
| Hystrix | 为路由引入Hystrix的断路器保护 | |
| FallbackHeaders | 为fallbackUri的请求头中添加具体的异常信息 | |
| PrefixPath | 为原始请求路径添加前缀 | |
| PreserveHostHeader | 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host | |
| RequestRateLimiter | 用于对请求限流,限流算法为令牌桶 | |
| RedirectTo | 将原始请求重定向到指定的URL | |
| RemoveHopByHopHeadersFilter | 为原始请求删除IETF组织规定的一系列Header | 默认就会启用,可以通过配置指定仅删除哪些Header |
| RemoveRequestHeader | 为原始请求删除某个Header | |
| RemoveResponseHeader | 为原始响应删除某个Header | |
| RewritePath | 重写原始的请求路径 | |
| RewriteResponseHeader | 重写原始响应中的某个Header | |
| SaveSession | 在转发请求之前,强制执行WebSession::save操作 | |
| SecureHeaders | 为原始响应添加一系列起安全作用的响应头 | |
| SetPath | 修改原始的请求路径 | |
| SetResponseHeader | 修改原始响应中某个Header的值 | |
| SetStatus | 修改原始响应的状态码 | |
| StripPrefix | 用于截断原始请求的路径 | |
| Retry | 针对不同的响应进行重试 | |
| RequestSize | 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large | 请求包大小,单位为字节,默认值为5M |
| ModifyRequestBody | 在转发请求之前修改原始请求体内容 | |
| ModifyResponseBody | 修改原始响应体的内容 | |
| Default | 为所有路由添加过滤器 | 也就是说通过Default Filter所配置的过滤器工厂会作用到所有的路由上 |
| MapRequestHeader | 添加一个新的header,其值为一个已经存在的header的值。 | fromHeader和toHeader两个参数 |
注意:每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory结尾,这是Spring Cloud Gateway的一个约定,例如AddRequestHeader对应的实现类为AddRequestHeaderGatewayFilterFactory。对源码感兴趣的小伙伴就可以按照这个规律拼接出具体的类名,以此查找这些内置过滤器工厂的实现代码
使用方法举例
1 | spring: |
这样即可为原始请求添加名为 My-Header ,值为 Hello的请求头
配置默认过滤器,即Default的用法
1 | spring: |
GlobalFilter
不需要进行配置,默认已经生效了。
但我们必须了解其功能,以备不时之需。
ForwardRoutingFilter
这个过滤器会根据formord模式规则将情况转发给DispatcherHandler,然后转发给gateway网关自己的服务中
处理uri的scheme是forward的请求
forward模式就是forward:///localendpoint这种形式
举个例子来理解
1 | - id: forward_routing_filter |
还要在gateway项目中创建个服务
1 | @RestController |
我们输入http://localhost:8080/forwardFilterTest进行测试。这个请求最终会进到/gateway/app这个服务中
因为在spring-cloud-gateway服务收到请求之后,会执行以下步骤
根据请求路径/forwardFilterTest匹配到路由forward_routing_filter,并将请求跳转为:http://localhost:8080/app
filters里面的PrefixPath配置请求改写为:http://localhost:8080/gateway/app
ForwardRoutingFilter过滤器中判断路由中有foroward://前缀,将请求转发给DispatcherHandler
DispatcherHandler匹配并转到spring-cloud-gateway服务中的contoller匹配的路径
总之,这种转发的重点在于转发给了gateway本身项目的服务。
使用场景不多。
LoadBalancerClientFilter
负载均衡过滤器。这个是非常常用到的过滤器。
因为网关后面的服务可以启动多个实例,使用负载均衡过滤器可以自动根据负载均衡规则路由到某台服务实例上面。
处理uri的scheme是lb的请求
使用这个过滤器的规则就是匹配到负载均衡的模式,即lb://xxx
举个例子
1 | spring: |
uri写为lb://service,即可在转发时使用ReactiveLoadBalancerClientFilter 。
service的名字即为spring.application.name的值
注意:默认情况下,如果LoadBalancer根据配置的实例名找不到有效的服务实例,返回状态码503,如果你想配置返回404,可以这样设置:
1 | spring.cloud.gateway.loadbalancer.use404=true |
NettyRoutingFilter
这是一个优先级最低的过滤器。
1 | @Override |
处理uri的sechme说http或者https的请求。
因为他的优先级最低,也就是pre流程的最后一个filter。它将使用Netty的HttpClient创建向下执行的请求代理。
前面说过,请求分为pre过程和post过程。那么springcloud-gateway是怎么区分一个请求目前是处在那个过程的呢?
答案就在NettyRoutingFilter里。
NettyRoutingFilter是请求进来进行处理的最后一个filter,所以在NettyRoutingFilter的代码中,
1 | exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection); |
会加上CLIENT_RESPONSE_CONN_ATTR一个属性。
之后的请求都带上这个属性,springcloud-gateway判断有这个属性的就是post类型的filter。比如下面的NettyWriteResponseFilter
NettyWriteResponseFilter
它的优先级是最高的。所以他是在前面的filter。
并且他是post类型的过滤器。也就相当于是进行响应处理的最后一个filter
经过他之后,就将响应的数据发送给网关的客户端了。
1 | public static final int WRITE_RESPONSE_FILTER_ORDER = -1; |
为什么他是post类型的过滤器?
上面说到springcloud-gateway判断有CLIENT_RESPONSE_CONN_ATTR属性的就是post类型的filter
看源码
1 | Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR); |
NettyWriteResponseFilter会判断CLIENT_RESPONSE_CONN_ATTR属性,如果没有,直接返回不做任何处理。
所以,因为NettyWriteResponseFilter的order是-1。
一般会排在最前面,所以请求首先会进来,但是因为当前没有CLIENT_RESPONSE_CONN_ATTR属性,所以就算经过NettyWriteResponseFilter也不会做任何处理。
等到过了NettyRoutingFilter,加上了CLIENT_RESPONSE_CONN_ATTR属性,再回来的时候就会得到NettyWriteResponseFilter的处理了。这也就是post过程了。
WebsocketRoutingFilter
很明显处理websocket的过滤器。
处理uri的scheme是ws或wss的请求。
1 | - id: websocket_route |
也可以对ws进行负载均衡,比如:lb:ws://serviceid
RouteToRequestUrlFilter
处理的是请求的属性中有gatewayRoute这个属性的请求。
它的作用是根据route的uri配置,重新修改请求的URL地址
比如浏览器请求网关的URL是:http://localhost:8080/app-a/app/balance,
路由的URI配置是:uri: lb://app-a
那么修改之后的路由的URI是:lb://app-a/app/balance