拦截器和 Filter 到底谁先谁后?preHandle 返回 false 之后会发生什么?404 的请求能不能被拦住?在 Filter 里读了请求体为什么 Controller 就读不到了?这篇在 Spring Boot 4.0.8 的 Spring MVC 7.0.9 上逐个打印执行顺序。
GET /api/hi → 200 hi
F1 进入 /api/hi [REQUEST]
F2 进入 /api/hi [REQUEST]
Once(OncePerRequestFilter) 进入 /api/hi [REQUEST]
A.preHandle [REQUEST] handler=hi
B.preHandle [REQUEST] handler=hi
Controller /api/hi
B.postHandle
A.postHandle
B.afterCompletion
A.afterCompletion
F2 返回
F1 返回
GET /open/hi → 200 open
F1 进入 /open/hi [REQUEST]
F2 进入 /open/hi [REQUEST]
Once(OncePerRequestFilter) 进入 /open/hi [REQUEST]
A.preHandle [REQUEST] handler=open
Controller /open/hi
A.postHandle
A.afterCompletion
F2 返回
F1 返回Filter → 拦截器 preHandle(升序)→ Controller → postHandle、afterCompletion(倒序)→ Filter 返回。
GET /api/hi → 403
F1 进入 /api/hi [REQUEST]
F2 进入 /api/hi [REQUEST]
Once(OncePerRequestFilter) 进入 /api/hi [REQUEST]
A.preHandle [REQUEST] handler=hi
B.preHandle [REQUEST] handler=hi
B 返回 false,中止
A.afterCompletion
F2 返回
F1 返回preHandle 返回 false 后只对已返回 true 的拦截器调用 afterCompletion。
GET /nope → 404 {"timestamp":"2026-10-19T03:34:18.256Z",
F1 进入 /nope [REQUEST]
F2 进入 /nope [REQUEST]
Once(OncePerRequestFilter) 进入 /nope [REQUEST]
A.preHandle [REQUEST] handler=ResourceHttpRequestHandler
A.afterCompletion
F2 返回
F1 返回
GET /static-missing.css → 404 {"timestamp":"2026-10-19T03:34:18.477Z",
F1 进入 /static-missing.css [REQUEST]
F2 进入 /static-missing.css [REQUEST]
Once(OncePerRequestFilter) 进入 /static-missing.css [REQUEST]
F2 返回
F1 返回Filter 对所有请求生效,拦截器只对匹配路径、有处理器的请求生效,并能拿到 HandlerMethod。
POST /api/body → 200 got:payload
F1 进入 /api/body [REQUEST]
F2 进入 /api/body [REQUEST]
Once(OncePerRequestFilter) 进入 /api/body [REQUEST]
A.preHandle [REQUEST] handler=body
B.preHandle [REQUEST] handler=body
Controller 读到 body = payload
B.postHandle
A.postHandle
B.afterCompletion
A.afterCompletion
F2 返回
F1 返回Servlet 输入流只能读一次,Filter 里读 body 要用缓存包装类。
POST /api/body → 400 {"timestamp":"2026-10-19T03:34:20.710Z",
F1 进入 /api/body [REQUEST]
F2 进入 /api/body [REQUEST]
Once(OncePerRequestFilter) 进入 /api/body [REQUEST]
BodyReader 在 Filter 里把请求体读完了:payload
A.preHandle [REQUEST] handler=body
B.preHandle [REQUEST] handler=body
B.afterCompletion
A.afterCompletion
F2 返回
F1 返回Filter 读完 body,@RequestBody 读不到,返回 400。