Java请求拦截流程如何规范

wen java案例 28

本文目录导读:

Java请求拦截流程如何规范

  1. 核心原则
  2. 标准流程与执行顺序
  3. 常见场景的规范实现
  4. 实战代码示例(Spring Boot)
  5. 最佳实践总结

在Java Web开发中,规范请求拦截流程的核心在于分层治理、职责清晰、有序执行,下面我从核心原则、标准流程(Filter/Interceptor)、常见场景规范以及代码示例四个维度来梳理。


核心原则

  1. 单一职责:每个拦截器只负责一件事(如仅做登录校验,不做权限判断)。
  2. 顺序敏感:拦截器链的执行顺序至关重要(如:日志 -> 鉴权 -> 限流 -> 业务处理)。
  3. 无状态:拦截器内不持有用户状态,用户信息通过 ThreadLocal 或请求属性传递。
  4. 快速失败:非核心功能(如日志)失败不应阻塞主流程,但核心功能(如鉴权)失败必须阻断。
  5. 性能可控:避免在拦截器中做耗时操作(如复杂计算、远程调用),必要时应引入缓存或异步。

标准流程与执行顺序

Filter(过滤器)层面(Servlet 规范)

通常用于最底层、跨切面的粗粒度处理,如字符编码、跨域、安全防护。

[客户端请求]
    ↓
[Filter 1: CharacterEncodingFilter]   // 设置编码
    ↓
[Filter 2: CorsFilter]               // 跨域处理
    ↓
[Filter 3: SecurityFilter]           // XSS/CSRF 防护
    ↓
[DispatcherServlet]                  // 进入 Spring MVC
    ↓
[Interceptor 1: LogInterceptor]      // 请求日志(前置)
    ↓
[Interceptor 2: AuthInterceptor]     // 登录/Token 校验
    ↓
[Interceptor 3: RateLimitInterceptor] // 限流
    ↓
[Controller]                         // 业务处理
    ↓
[Interceptor 3: 后置]                // 限流后置(通常无操作)
    ↓
[Interceptor 2: 后置]                // 鉴权后置(通常无操作)
    ↓
[Interceptor 1: 后置/完成]           // 日志记录结束时间
    ↓
[Filter 响应链] out

Interceptor(拦截器)层面(Spring MVC 专属)

更贴近业务逻辑,可灵活操作 ModelAndView,适合做:身份校验、权限控制、日志审计、参数预处理

  • preHandle:请求前,返回 true 放行,返回 false 阻断。
  • postHandle:Controller 执行后、视图渲染前。
  • afterCompletion:视图渲染后、请求完全结束前(通常用于资源清理)。

常见场景的规范实现

鉴权拦截规范

  • Token 校验:从 Header 或 Cookie 提取,验证签名和过期时间。
  • ThreadLocal 传递用户信息:防止数据污染,请求结束务必 remove()
  • 白名单过滤:登录、注册、静态资源等接口应跳过鉴权。

日志审计规范

  • 必须记录:请求路径、请求参数、响应状态码、耗时、用户ID(如有)。
  • 必须脱敏:密码、身份证、手机号等敏感字段在记录前做 处理。
  • 异步写入:建议通过消息队列或异步线程写日志,避免阻塞主流程。

参数校验与防篡改规范

  • 前置参数校验:使用 @Valid 或自定义验证器,快速返回错误。
  • 签名校验:对于敏感接口,对请求体 + 时间戳做 HMAC 签名验证,防止重放攻击。

限流与防刷规范

  • 基于 IP 或 Token:使用桶算法(RateLimiter)或滑动窗口。
  • 优先级低于鉴权:正确区分“未登录的游客”和“已登录的恶意用户”。

实战代码示例(Spring Boot)

定义自定义拦截器(Token 校验 + 日志)

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1. 白名单放行
        String uri = request.getRequestURI();
        if (uri.startsWith("/api/public/") || uri.equals("/login")) {
            return true;
        }
        // 2. 提取 Token
        String token = request.getHeader("Authorization");
        if (token == null || !jwtUtil.validateToken(token)) {
            response.setStatus(401);
            response.getWriter().write("{\"code\":401,\"msg\":\"未授权\"}");
            return false;
        }
        // 3. 解析用户,存入 ThreadLocal
        User user = jwtUtil.parseUser(token);
        UserContext.set(user);
        // 4. 记录请求日志(简单示例)
        log.info("用户: {} 请求: {}", user.getId(), uri);
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 必须清理 ThreadLocal,防止内存泄漏
        UserContext.remove();
    }
}

注册拦截器并指定顺序

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private AuthInterceptor authInterceptor;
    @Autowired
    private RateLimitInterceptor rateLimitInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 顺序1:日志拦截器(最先执行)
        registry.addInterceptor(logInterceptor)
                .addPathPatterns("/**");
        // 顺序2:限流拦截器
        registry.addInterceptor(rateLimitInterceptor)
                .addPathPatterns("/api/**")
                .order(1);
        // 顺序3:鉴权拦截器(最后执行,保证已限流)
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/public/**", "/login")
                .order(2);
    }
}

使用 Filter 做全局限流(可选)

@Component
@Order(1) // 优先级最高
public class RateLimitFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        String ip = request.getRemoteAddr();
        if (!rateLimiter.tryAcquire(ip)) {
            response.setStatus(429);
            return;
        }
        chain.doFilter(request, response);
    }
}

最佳实践总结

场景 使用位置 备注
跨域、编码 Filter 与业务无关,全局生效
XSS/CSRF Filter 安全基座
Token 校验 Interceptor preHandle 业务相关,可获取 Spring 容器
权限校验 Interceptor preHandle 依赖当前登录用户
请求日志 Interceptor preHandle 可记录请求前/后时间
参数脱敏 Interceptor afterCompletion 响应体已生成
全局异常 @ControllerAdvice 不放在拦截器中
性能不好的操作 异步队列 不要阻塞拦截流程

最后总结一句话:

“Filter 做底层安全与编码,Interceptor 做登录与权限,业务逻辑放 Controller,异常统一由 @ControllerAdvice 处理。”

如果你需要针对某个具体场景(如微服务下如何利用网关统一拦截、或如何设计防重放拦截),可以告诉我,我可以进一步展开。

抱歉,评论功能暂时关闭!