在分布式系统开发中,请求响应拦截器链(Interceptor Chain)是处理前后端通信的关键基础设施。它像流水线上的质检员,对每个经过的请求和响应进行统一处理。我经历过多个从零搭建的微服务项目,拦截器链的设计质量直接影响着系统的可维护性和扩展性。
典型的拦截器链工作流程是这样的:当HTTP请求到达服务端时,会依次通过预先注册的拦截器,每个拦截器都能对请求进行修改或阻断;当服务端生成响应后,这些拦截器又会以相反的顺序对响应进行处理。这种设计模式完美符合开闭原则——需要新增功能时,只需添加新的拦截器而不用修改现有代码。
在电商系统中,我们使用JWT拦截器验证用户令牌。具体实现时要注意:
java复制public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
try {
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
request.setAttribute("userId", claims.getSubject());
return true;
} catch (Exception e) {
response.setStatus(401);
return false;
}
}
}
关键点:令牌解析失败时要立即终止请求链,避免后续不必要的处理
全链路日志拦截器需要记录:
实测案例:某次线上故障排查时,通过日志拦截器记录的耗时数据,快速定位到某个第三方接口响应缓慢导致整体超时。
金融类系统常用加解密拦截器:
避坑指南:加解密算法要支持热更新,避免算法升级导致服务不可用
Spring通过HandlerInterceptor接口提供三个关键切入点:
preHandle:控制器方法执行前postHandle:控制器方法执行后afterCompletion:请求完成后注册拦截器的正确姿势:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/static/**");
}
}
通过order属性控制顺序:
java复制registry.addInterceptor(new AuthInterceptor()).order(1);
registry.addInterceptor(new LogInterceptor()).order(2);
执行顺序规则:
在WebFlux异步环境中,需要实现WebFilter接口:
java复制public class ReactiveAuthFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
WebFilterChain chain) {
return Mono.just(exchange)
.flatMap(this::checkAuth)
.then(chain.filter(exchange));
}
}
示例测试用例:
java复制@Test
void testAuthInterceptor_ValidToken() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", validToken);
AuthInterceptor interceptor = new AuthInterceptor();
assertTrue(interceptor.preHandle(request, null, null));
assertEquals("123", request.getAttribute("userId"));
}
使用Spring Boot Test验证完整链路:
java复制@SpringBootTest
@AutoConfigureMockMvc
class InterceptorChainTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldBlockUnauthorizedRequest() throws Exception {
mockMvc.perform(get("/api/user"))
.andExpect(status().isUnauthorized());
}
}
在订单系统中,我们设计了这样的拦截器链:
每个拦截器保持单一职责,通过组合实现复杂业务逻辑。当需要新增风控规则时,只需新增风控拦截器实现,不会影响其他业务逻辑。
经验之谈:拦截器之间应该通过请求属性(request attribute)传递数据,而不是使用全局变量,避免线程安全问题
使用Arthas工具监控拦截器耗时:
bash复制trace org.springframework.web.servlet.HandlerInterceptor *
特别注意:
支持动态调整的拦截器链:
java复制public class DynamicInterceptorChain {
private List<Interceptor> interceptors = new CopyOnWriteArrayList<>();
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public void process(Request request) {
for (Interceptor interceptor : interceptors) {
if (!interceptor.handle(request)) {
break;
}
}
}
}
在需要更细粒度控制时,可以组合使用:
这种组合在权限控制场景特别有用:拦截器做基础认证,AOP做方法级权限校验。
完善的监控体系应该包括:
推荐使用Micrometer实现指标收集:
java复制public class MonitoringInterceptor implements HandlerInterceptor {
private final Counter authFailureCounter;
public MonitoringInterceptor(MeterRegistry registry) {
authFailureCounter = registry.counter("auth.failure.count");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
if (response.getStatus() == 401) {
authFailureCounter.increment();
}
}
}
在选择拦截器实现方案时,需要权衡:
在最近的项目中,我们最终选择了Spring拦截器+自定义注解的方案,因为:
这个方案在保持扩展性的同时,将性能损耗控制在3%以内。