zuul过滤器
Zuul 过滤器:请求生命周期的全方位管控
Zuul 的核心能力源于其灵活的过滤器机制,通过在请求处理的不同阶段插入自定义逻辑,实现对请求的路由、校验、监控等全方位管控。Zuul 将过滤器分为四类,分别对应请求生命周期的不同阶段,共同构成了网关的核心扩展点。
Zuul 过滤器的四种类型
Zuul 过滤器按执行时机可分为pre、route、post、error四类,覆盖了请求从进入网关到返回响应的全流程:
| 过滤器类型 | 执行阶段 | 典型应用场景 |
|---|---|---|
| pre | 请求被路由到微服务之前执行 | 身份认证(如 Token 校验)、参数校验、限流、请求转发、设置上下文变量等。 |
| route | 请求被路由到微服务过程中执行 | 处理请求转发逻辑(如选择具体服务实例、修改请求参数 / 头信息、适配不同协议)。 |
| post | 请求被微服务处理之后执行 | 统一添加响应头、收集监控指标(如响应时间)、日志记录、结果二次处理等。 |
| error | 上述任一阶段发生异常时执行 | 统一错误处理(如转换异常为标准响应格式)、记录错误日志、触发降级等。 |
过滤器的执行流程
Zuul 过滤器的执行顺序由filterOrder()(数值越小越先执行)和类型共同决定,核心流程如下:
// Zuul核心过滤器执行逻辑(简化版)
public void doFilter(...) {
try {
// 1. 执行pre类型过滤器
preRouting();
// 2. 若允许路由,执行route类型过滤器(转发请求到微服务)
if (sendZuulResponse) {
routing();
}
// 3. 执行post类型过滤器(处理响应)
postRouting();
} catch (ZuulException e) {
// 4. 任何阶段发生异常,执行error类型过滤器
error(e);
}
}
- 异常处理:无论 pre、route、post 阶段抛出异常,都会触发 error 过滤器,执行后若未解决异常,最终仍会进入 post 阶段(确保响应正常返回)。
自定义 Zuul 过滤器
自定义过滤器需继承ZuulFilter抽象类,实现四个核心方法。以下通过实例说明不同类型过滤器的实现。
1. 自定义 pre 过滤器(身份认证)
功能:请求路由前校验 Token,无 Token 或 Token 无效则拦截请求。
// 注册为Spring Bean
public class AuthPreFilter extends ZuulFilter {
// 过滤器类型:pre
public String filterType() {
return "pre";
}
// 执行顺序:1(数值越小越先执行)
public int filterOrder() {
return 1;
}
// 是否启用过滤器:true(始终启用)
public boolean shouldFilter() {
return true;
}
// 核心逻辑:校验Token
public Object run() throws ZuulException {
// 获取请求上下文(存储请求/响应信息的容器)
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
// 从请求参数或头信息中获取Token
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
// 拦截请求:不转发到微服务
ctx.setSendZuulResponse(false);
// 设置响应状态码(401未授权)
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
// 设置响应体
ctx.setResponseBody("Missing or invalid token");
// 设置响应类型
ctx.getResponse().setContentType("application/json");
}
return null; // 无返回值(通过RequestContext传递状态)
}
}
2. 自定义 post 过滤器(响应处理)
功能:微服务返回响应后,统一添加响应头(如X-Gateway-Version)。
public class ResponsePostFilter extends ZuulFilter {
public String filterType() {
return "post"; // post类型
}
public int filterOrder() {
return 1; // 执行顺序
}
public boolean shouldFilter() {
return true;
}
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletResponse response = ctx.getResponse();
// 添加自定义响应头
response.addHeader("X-Gateway-Version", "1.0.0");
return null;
}
}
3. 自定义 error 过滤器(统一错误处理)
功能:捕获异常并返回标准化错误响应。
public class ErrorFilter extends ZuulFilter {
public String filterType() {
return "error";
}
public int filterOrder() {
return 1;
}
public boolean shouldFilter() {
// 仅当存在异常时启用
return RequestContext.getCurrentContext().containsKey("error.exception");
}
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
Throwable exception = (Throwable) ctx.get("error.exception");
// 构建标准化错误响应
String errorMsg = exception.getMessage() != null ? exception.getMessage() : "Unknown error";
int statusCode = HttpStatus.INTERNAL_SERVER_ERROR.value();
// 适配不同异常类型(如自定义业务异常)
if (exception instanceof BusinessException) {
statusCode = ((BusinessException) exception).getCode();
}
// 设置响应
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(statusCode);
ctx.setResponseBody("{\"code\":" + statusCode + ",\"message\":\"" + errorMsg + "\"}");
ctx.getResponse().setContentType("application/json");
return null;
}
}
过滤器的核心组件:RequestContext
RequestContext是 Zuul 过滤器间传递数据的核心容器,本质是一个ThreadLocal变量,存储了请求 / 响应的上下文信息,主要方法包括:
| 方法 | 作用 |
|---|---|
setSendZuulResponse(boolean) |
设置是否转发请求到微服务(false表示拦截)。 |
setResponseStatusCode(int) |
设置响应状态码(如 401、500)。 |
setResponseBody(String) |
设置响应体内容。 |
getResponse() |
获取HttpServletResponse对象,用于操作响应头、编码等。 |
getRequest() |
获取HttpServletRequest对象,用于获取请求参数、头信息等。 |
put(String key, Object value) |
存储自定义变量(供其他过滤器使用)。 |
禁用默认过滤器
Zuul 默认启用了一些内置过滤器(如ServletDetectionFilter、FormBodyWrapperFilter),若需禁用某过滤器,可在配置文件中设置:
zuul:
# 禁用指定过滤器(格式:过滤器类名.类型.disable: true)
ServletDetectionFilter:
pre:
disable: true # 禁用pre类型的ServletDetectionFilter
FormBodyWrapperFilter:
pre:
disable: true # 禁用pre类型的FormBodyWrapperFilter
- 内置过滤器类名可在
org.springframework.cloud.netflix.zuul.filters包中查看。
过滤器的注意事项
- 线程安全:
RequestContext基于ThreadLocal,过滤器逻辑需保证线程安全; - 性能影响:过滤器执行时间会累加在请求响应时间中,避免复杂逻辑(如耗时数据库操作);
- 执行顺序:通过
filterOrder()控制同一类型过滤器的执行顺序,建议按功能分组(如认证过滤器 order=1,限流过滤器 order=2); - 异常处理:
run()方法抛出的异常会触发 error 过滤器,需确保异常信息可被正确解析。
总结
Zuul 过滤器通过 pre、route、post、error 四种类型,实现了对请求全生命周期的干预,是网关实现身份认证、限流、监控等功能的核心机制。自定义过滤器时,需明确其类型和执行顺序,通过RequestContext传递上下文信息,并注意性能和线程安全