Spring中如何判断静态资源请求?实现日志过滤非静态资源
这问题我在做Spring后端项目时也碰到过——既要完整记录业务接口的请求日志,又不想让CSS、JS、图片这类静态资源的请求把日志堆得乱糟糟的。试过扩展名判断确实有漏洞,比如有些静态资源可能不带扩展名(比如某些CDN返回的资源),纠结请求头的性能问题也很正常,其实有几个既高效又靠谱的方法:
方案一:复用Spring静态资源配置的路径匹配
Spring MVC本身就有专门的静态资源映射配置(比如WebMvcConfigurer的addResourceHandlers),我们可以直接复用这些配置好的路径规则来判断是否跳过日志,这是最省心也高效的方式:
- 先在你的Web配置类里明确静态资源的路径映射:
@Configuration public class WebConfig implements WebMvcConfigurer { // 定义静态资源路径,比如/static/**、/assets/**、/images/**等 private static final List<String> STATIC_RESOURCE_PATHS = Arrays.asList( "/static/**", "/assets/**", "/images/**", "/css/**", "/js/**" ); @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); // 其他静态资源映射... } // 提供路径匹配器和静态资源路径,供日志拦截器使用 @Bean public PathMatcher pathMatcher() { return new AntPathMatcher(); } @Bean public List<String> staticResourcePaths() { return STATIC_RESOURCE_PATHS; } }
- 在你的请求日志拦截器里,注入
PathMatcher和静态资源路径列表,在preHandle方法里快速匹配:
@Component public class RequestLogInterceptor implements HandlerInterceptor { private final PathMatcher pathMatcher; private final List<String> staticResourcePaths; public RequestLogInterceptor(PathMatcher pathMatcher, List<String> staticResourcePaths) { this.pathMatcher = pathMatcher; this.staticResourcePaths = staticResourcePaths; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestPath = request.getRequestURI(); // 检查请求路径是否匹配任意静态资源规则 boolean isStaticResource = staticResourcePaths.stream() .anyMatch(path -> pathMatcher.match(path, requestPath)); if (isStaticResource) { // 跳过日志记录,直接放行 return true; } // 执行业务请求的日志记录逻辑... return true; } }
这种方式的优势在于:路径匹配用的是Spring优化过的AntPathMatcher,性能非常高;而且完全和项目的静态资源配置保持一致,不会出现遗漏或误判。
方案二:通过Handler类型判断(最准确)
Spring处理静态资源请求时,会使用ResourceHttpRequestHandler这个处理器。我们可以直接在拦截器里判断当前请求的handler是否是这个类型,是的话就跳过日志:
@Component public class RequestLogInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断是否是静态资源处理器 if (handler instanceof ResourceHttpRequestHandler) { return true; // 跳过日志 } // 业务请求日志记录逻辑... return true; } }
这个方案不需要额外配置任何路径,完全依赖Spring自身的请求处理逻辑,最准确——不管静态资源有没有扩展名、路径是什么,只要Spring认为它是静态资源,就会用ResourceHttpRequestHandler处理,我们直接跳过即可。而且只是一个简单的类型判断,性能开销可以忽略不计。
方案三:轻量级请求头判断(补充方案)
你担心检查请求头影响性能其实多虑了——读取请求头是非常轻量的操作,几乎不会有性能损耗。可以结合Accept请求头来快速过滤大部分静态资源:
@Component public class RequestLogInterceptor implements HandlerInterceptor { private static final Set<String> STATIC_CONTENT_TYPES = new HashSet<>(Arrays.asList( "text/css", "application/javascript", "image/", "font/" )); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String acceptHeader = request.getHeader("Accept"); if (acceptHeader != null) { // 判断Accept头是否包含静态资源类型 boolean isStatic = STATIC_CONTENT_TYPES.stream() .anyMatch(type -> acceptHeader.contains(type)); if (isStatic) { return true; } } // 业务请求日志记录逻辑... return true; } }
这个方案适合静态资源路径不固定的场景,但可能存在少量误判(比如某些动态接口也可能返回image/*类型),建议和方案一或方案二结合使用。
总结下来,方案二是最优选择——既不需要额外配置,判断逻辑简单高效,又能准确识别所有Spring处理的静态资源请求,完全解决你提到的无扩展名静态资源的问题,性能也毫无压力。
内容的提问来源于stack exchange,提问作者Christopher Schneider

