0%

zuul过滤器

Zuul 过滤器:请求生命周期的全方位管控

Zuul 的核心能力源于其灵活的过滤器机制,通过在请求处理的不同阶段插入自定义逻辑,实现对请求的路由、校验、监控等全方位管控。Zuul 将过滤器分为四类,分别对应请求生命周期的不同阶段,共同构成了网关的核心扩展点。

Zuul 过滤器的四种类型

Zuul 过滤器按执行时机可分为pre、route、post、error四类,覆盖了请求从进入网关到返回响应的全流程:

过滤器类型 执行阶段 典型应用场景
pre 请求被路由到微服务之前执行 身份认证(如 Token 校验)、参数校验、限流、请求转发、设置上下文变量等。
route 请求被路由到微服务过程中执行 处理请求转发逻辑(如选择具体服务实例、修改请求参数 / 头信息、适配不同协议)。
post 请求被微服务处理之后执行 统一添加响应头、收集监控指标(如响应时间)、日志记录、结果二次处理等。
error 上述任一阶段发生异常时执行 统一错误处理(如转换异常为标准响应格式)、记录错误日志、触发降级等。

过滤器的执行流程

Zuul 过滤器的执行顺序由filterOrder()(数值越小越先执行)和类型共同决定,核心流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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 无效则拦截请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Component // 注册为Spring Bean
public class AuthPreFilter extends ZuulFilter {

// 过滤器类型:pre
@Override
public String filterType() {
return "pre";
}

// 执行顺序:1(数值越小越先执行)
@Override
public int filterOrder() {
return 1;
}

// 是否启用过滤器:true(始终启用)
@Override
public boolean shouldFilter() {
return true;
}

// 核心逻辑:校验Token
@Override
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)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Component
public class ResponsePostFilter extends ZuulFilter {

@Override
public String filterType() {
return "post"; // post类型
}

@Override
public int filterOrder() {
return 1; // 执行顺序
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
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 过滤器(统一错误处理)

功能:捕获异常并返回标准化错误响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Component
public class ErrorFilter extends ZuulFilter {

@Override
public String filterType() {
return "error";
}

@Override
public int filterOrder() {
return 1;
}

@Override
public boolean shouldFilter() {
// 仅当存在异常时启用
return RequestContext.getCurrentContext().containsKey("error.exception");
}

@Override
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 默认启用了一些内置过滤器(如ServletDetectionFilterFormBodyWrapperFilter),若需禁用某过滤器,可在配置文件中设置:

1
2
3
4
5
6
7
8
zuul:
# 禁用指定过滤器(格式:过滤器类名.类型.disable: true)
ServletDetectionFilter:
pre:
disable: true # 禁用pre类型的ServletDetectionFilter
FormBodyWrapperFilter:
pre:
disable: true # 禁用pre类型的FormBodyWrapperFilter
  • 内置过滤器类名可在org.springframework.cloud.netflix.zuul.filters包中查看。

过滤器的注意事项

  1. 线程安全RequestContext基于ThreadLocal,过滤器逻辑需保证线程安全;
  2. 性能影响:过滤器执行时间会累加在请求响应时间中,避免复杂逻辑(如耗时数据库操作);
  3. 执行顺序:通过filterOrder()控制同一类型过滤器的执行顺序,建议按功能分组(如认证过滤器 order=1,限流过滤器 order=2);
  4. 异常处理run()方法抛出的异常会触发 error 过滤器,需确保异常信息可被正确解析。

总结

Zuul 过滤器通过 pre、route、post、error 四种类型,实现了对请求全生命周期的干预,是网关实现身份认证、限流、监控等功能的核心机制。自定义过滤器时,需明确其类型和执行顺序,通过RequestContext传递上下文信息,并注意性能和线程安全

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10