过滤器类型与请求生命周期
PRE
:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。ROUTING
:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient
或Netfilx Ribbon
请求微服务。POST
:这种过滤器在路由到微服务后执行。这种过滤器可用来为响应添加标准的HTTP Header
、收集统计信息和指标、将响应从微服务发送给客户端等。ERROR
:在其他阶段发生错误时执行该过滤器。
除了默认的过滤器类型,Zuul
还允许创建自定义的过滤器类型。例如,可以定制一种STATIC
类型的过滤器,直接在Zuul
中生成响应,而不将请求转发到后端的微服务。
内置过滤器详解
@EnableZuulProxy
是最常用的注解,是@EnableZuulServer
的增强版。
RequestContext
扩展了ConcurrentHashMap
,用于在过滤器之间传递消息。它的数据保存在每个请求的ThreadLocal
中。用于存储请求路由到哪里、错误、HttpServlet
、HttpServletResponse
等信息。
@EnableZuulServer
所启用的过滤器
- pre 类型过滤器
ServletDetectionFilter
:该过滤器用于检查请求是否通过Spring Dispatcher
。检查后,通过FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY
(isDispatcherServletRequest
)设置布尔值。FormBodyWrapperFilter
:解析表单数据,并为请求重新编码。DebugFilter
:顾名思义,调试用的过滤器,当设置zuul.include-debug-header=true
或zuul.debug.request=true
,并在请求时,加上debug=true
的参数,例如$ZUUL_HOST:ZUUL_PORT/path?debug=true
,就会开启该过滤器。该过滤器就会把RequestContext.setDebugRouting()
、RequestContext.setDebugRequest()
设为 true。
- route 类型过滤器
SendForwardFilter
:该过滤器使用Servlet RequestDispatcher
转发请求,转发位置存储在RequestContext
的属性FilterConstants.FOREWARD_TO_KEY
中。这对转发到Zuul
自身的端点很有用。可以将路由改成:
zuul:
routes:
abc:
path: /path-a/**
url: forward:/path-b
然后访问$ZUUL_HOST:ZUUL_PORT/path-a
,观察该过滤器的执行过程。
- post 类型过滤器
SendResponseFilter
:将Zuul
所代理请求的的响应写入当前响应。
- error 类型过滤器
SendErrorFilter
:如果RequestContext.getThrowable()
不为 null,那么默认就会转发到/error
,也可以设置error.path
属性修改默认的转发路径。
@EnableZuulProxy
所启用的过滤器
如果使用注解@EnableZuulProxy
,那么除上述过滤器之外,Spring Cloud
还会安装以下过滤器:
- pre 类型过滤器
PreDecorationFilter
:该过滤器根据提供的RouteLocator
确定路由到的地址,以及怎样去路由。该路由器也可为后端请求设置各种代理相关的 header。
- route 类型过滤器
RibbonRoutingFilter
:该过滤器使用Ribbon
,Hystrix
和可插拔的 HTTP 客户端发送请求。serviceId 在RequestContext
的属性FilterConstants.SERVICE_ID_KEY
(RequestContext.getCurrentContext().get("serviceId")
) 中。该过滤器可使用不同的 HTTP 客户端。
Apache HttpClient
:默认的 HTTP 客户端。Squareup OkHttpClient v3
:如需使用该客户端,需保证com.squareup.okhttp3
的依赖在 classpath 中,并设置ribbon.okhttp.enabled = true
。Netflix Ribbon HTTP client
:设置ribbon.restclient.enabled = true
即可启用该 HTTP 客户端。需要注意的是,该客户端有一定限制,例如不支持 PATCH 方法,另外,它有内置的重试机制。
SimpleHostRoutingFilter
:该过滤器通过Apache HttpClient
向指定的 URL 发送请求。URL 在RequestContext.getRouteHost()
中。
编写Zuul
过滤器
- 编写自定义
Zuul
过滤器:
public class PreRequestLogFilter extends ZuulFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.class);
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
PreRequestLogFilter.LOGGER.info((String.format("send %s request to %s", request.getMethod(), request.getRequestURI())));
return null;
}
}
由代码可知,自定义的 Zuul Filter 需实现以下几个方法:
filterType
:返回过滤器的类型。有pre
、route
、post
、error
等几种取值,分别对应上文的几种过滤器。详细可以参考com.netflix.zuul.ZuulFilter.filterType()
中的注释。filterOrder
:返回一个 int 值来指定过滤器的执行顺序,不同的过滤器允许返回相同的数字。shouldFilter
:返回一个 boolean 值来判断该过滤器是否要执行,true 表示执行,false 表示不执行。run
:过滤器的具体逻辑。本例中,我们让它打印了请求的 HTTP 方法以及请求的地址。
- 在启动类上添加:
@Bean
public PreRequestLogFilter preRequestLogFilter() {
return new PreRequestLogFilter();
}
- 启动用户微服务,
访问http://127.0.0.1:8040/microservice-provider-user/1
,获得如下日志:
INFO 9107 --- [nio-8040-exec-3] c.i.z.m.PreRequestLogFilter : send GET request to /microservice-provider-user/1
说明自定义Zuul
过滤器被执行了。
禁用Zuul
过滤器
Spring Cloud
默认为Zuul
编写并启用了一些过滤器,例如DebugFilter
、FormBodyWrapperFilter
、PreDecorationFilter
等。这些过滤器都存放在spring-cloud-netflix-core
这个 Jar 包的org.springframework.cloud.netflix.zuul.filters
包中。
一些场景下,我们想要禁用掉部分过滤器,只需设置zuul.SimpleClassName
所对应的过滤器。以过滤器org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
为例,只需设置zuul.SendResponseFilter.post.disable=true ,即可禁用该过滤器。