SpringBoot单个请求触发拦截器多次执行致限流失效问题咨询
问题原因
从日志可以看出两次拦截的请求路径不一致:第一次为/original-article/similar-articles,第二次为多了一层前缀的/original-article/original-article/similar-articles,说明test环境下携带originalUrl参数时触发了Spring MVC内部转发,而你的拦截器匹配/**规则,会同时拦截原始请求和内部转发请求,导致逻辑执行两次。
触发内部转发的根本原因是dev和test环境的Spring MVC配置差异:
- 通常dev环境会开启
spring.mvc.throw-exception-if-no-handler-found=true、关闭静态资源映射,路径匹配失败会直接抛异常 - test环境默认关闭上述配置,当请求参数
originalUrl携带的完整URL包含//等特殊字符时,Spring MVC的路径匹配器会尝试做路径补全/转发,触发二次请求
另外你当前用HashMap存储访问频率属于线程不安全实现,高并发下会有逻辑错误,属于隐藏问题。
解决方案
1. 拦截器直接过滤内部转发请求
在FrequencyInterceptor的preHandle方法最前面增加转发判断,仅处理原始用户请求:
import javax.servlet.RequestDispatcher; // 放在方法最开头 if (request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) != null) { // 内部转发请求直接放行,不做频率校验 return true; }
2. 对齐dev/test环境的Spring MVC配置
修改test环境的application配置,避免Spring自动做路径补全:
spring: mvc: throw-exception-if-no-handler-found: true pathmatch: use-registered-suffix-pattern: true matching-strategy: ANT_PATH_MATCHER web: resources: add-mappings: false
3. 修复频率控制的线程安全问题
将存储访问时间的HashMap替换为ConcurrentHashMap,避免多线程并发修改导致的计数异常:
// 替换原有HashMap定义 private final Map<String, Long> frequency = new ConcurrentHashMap<>();
内容的提问来源于stack exchange,提问作者aszswaz
相关产品推荐
相关产品推荐

