4.6.3 MVC 拦截器
本节功能自 5.3.0 起提供。
net.hasor.web.HandlerInterceptor 只作用于已匹配 Action 的 MVC 请求。
HTTP 过滤器位于它的外层,静态资源和继续交给 Servlet 的请求不经过 MVC 拦截器。
注册与顺序
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(WebApiBinder binder) {
binder.bindInterceptor(new LoginInterceptor());
binder.bindInterceptor(new AuditInterceptor());
}
}
WebApiBinder.bindInterceptor(HandlerInterceptor interceptor) 按调用注册的先后顺序执行前置处理。
用户在 WebMvcConfigurer 实现中安排注册顺序,框架直接使用这一顺序。
上例的 Login 在 Audit 之前进入;后置处理和完成回调逆序执行。
拦截器实例会被多个请求共享,请求状态应保存到 Invoker 或请求属性中。
在模块配置期间完成注册,Web 上下文初始化时取得拦截器列表,请求执行时直接复用,无需逐次从容器查询。
使用 hasor-config 时,可在 WebMvcConfigurer.addInterceptors(WebApiBinder) 中使用同一注册 API。
生命周期
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(Invoker invoker) {
if (invoker.getHttpRequest().getUserPrincipal() == null) {
invoker.getHttpResponse().setStatus(401);
return false;
}
return true;
}
@Override
public void postHandle(Invoker invoker, Object result) {
// Inspect or replace Invoker.RETURN_DATA_KEY before rendering.
}
@Override
public void afterCompletion(Invoker invoker, Throwable failure) {
// Release resources acquired by this interceptor.
}
}
preHandle:在 Controller 之前按序执行。返回false表示请求已处理,停止后续拦截器、Controller 和自动渲染。postHandle:Controller 正常返回后逆序执行,之后才进行渲染。可通过invoker.put(Invoker.RETURN_DATA_KEY, result)修改最终结果。afterCompletion:渲染结束或请求中断后逆序执行,仅通知preHandle已返回true的拦截器。返回false或前置处理抛出异常的当前拦截器不参与该回调。
正常请求的执行顺序是:外层 Filter → 前置处理 → Controller → 逆序后置处理 → 渲染 → 逆序完成回调 → 返回外层 Filter。
preHandle、Controller 或 postHandle 失败时进入 MVC 异常处理。渲染在调用及异常处理结束后执行,渲染失败直接向外抛出,并传递给 afterCompletion。
调用正常结束或异常已解决,且渲染成功或被跳过时,完成回调的 failure 为 null;否则传入最终向外抛出的异常,包括渲染异常。不会为异常恢复结果补跑 postHandle。
完成回调自身失败只记录日志,其余完成回调继续执行。
自行响应与异步
取得响应 Writer 或输出流后,框架不再追加自动渲染内容。
前置拦截器只设置状态码或响应头、不输出正文时,返回 false 即可终止 MVC。
postHandle 可调用 invoker.setSkipRender() 跳过后续自动渲染,包括显式选择的渲染器和视图。
MVC 主链路在输出前完成检查,渲染器内部不判断该状态。
该方法不终止其余拦截器回调;preHandle 中需要终止 MVC 时仍应返回 false。
通过 invoker.isSkipRender() 查询状态。状态仅属于当前请求,一旦开启跳过渲染,就不能恢复渲染。
框架 @Async Action 的 MVC 回调在工作线程执行,响应输出限制见异步请求。
Action 自行调用 Servlet startAsync() 后,正常返回仍会执行 postHandle,但异步状态下不会自动渲染。afterCompletion 在当前 MVC 调用结束时执行,不会自动延迟到 Servlet 异步请求完成;异步完成、错误和超时应通过 Servlet AsyncListener 处理。
自行创建的异步任务不处于 MVC 异常处理的调用栈中。