You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已传请求参数仍间歇性抛出MissingServletRequestParameterException问题排查

问题描述

我有一个Spring Boot 2.7.3应用,定义了如下控制器:

@RestController
@EnableAutoConfiguration
public class TrainController {

    @CrossOrigin(origins = "http://localhost:3000")
    @RequestMapping(value = "/trains/history", method = RequestMethod.GET)
    public List<TrainStatus> getTrainStatusesForTimestamp(
            @RequestParam long timestamp
    ) {
        // do stuff
    }
}

调用该API端点通常正常,本地运行无问题,但在生产环境高负载场景下(比如并行重复调用该接口,同时大量调用应用中多控制器的其他API),日志中出现如下信息:

2022-09-06 20:48:37.939 DEBUG 19282 --- [https-openssl-nio-443-exec-10] o.s.w.f.CommonsRequestLoggingFilter      : Before request [GET /trains/history?timestamp=1662511707]
2022-09-06 20:48:37.945  WARN 19282 --- [https-openssl-nio-443-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'timestamp' for method parameter type long is not present]
2022-09-06 20:48:37.945 DEBUG 19282 --- [https-openssl-nio-443-exec-10] o.s.w.f.CommonsRequestLoggingFilter      : After request [GET /trains/history?timestamp=1662511707]

(上述CommonsRequestLoggingFilter的DEBUG日志来自我根据文档定义的Bean,用于确认必填的timestamp参数是否存在)

当抛出该异常时,响应为400 Bad Request。我已确认客户端确实携带了timestamp请求参数,Spring Boot应用日志也验证了这一点,但高负载下仍间歇性出现该异常。请问这是什么原因?是否触发了Tomcat的连接或线程限制?目前应用内存尚有充足余量。

原因分析

这种高负载下间歇性出现的参数丢失问题,并非Tomcat连接/线程限制直接导致,更可能是以下场景引发:

  • Filter拦截器提前读取请求流:若应用中存在自定义或第三方Filter(如监控、安全组件),在高负载并发场景下,这些Filter可能提前调用request.getParameter()或读取请求输入流。由于HttpServletRequest的输入流仅能读取一次,后续Spring MVC的参数解析器就无法正确获取参数,进而抛出缺失参数的异常。
  • Tomcat参数解析并发漏洞:极端高负载下,Tomcat内部的参数解析逻辑可能出现线程安全问题,导致parameterMap未正确填充查询参数。
  • 请求流转异常:若请求经过内部转发/重定向且未正确传递查询参数,也可能出现该现象,但结合日志中明确显示查询字符串存在的情况,此场景概率极低。
解决方案

针对上述可能的原因,可按以下步骤排查修复:

  1. 排查并修复Filter逻辑:

    • 检查所有注册的Filter,尤其是在CommonsRequestLoggingFilter之前执行的Filter,确认是否存在提前读取请求参数或输入流的操作。
    • 若存在此类操作,使用ContentCachingRequestWrapper包装请求,让参数可被多次读取。示例代码:
      @Component
      public class CustomCachingFilter extends OncePerRequestFilter {
          @Override
          protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
              ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
              filterChain.doFilter(wrappedRequest, response);
          }
      }
      
  2. 强制Tomcat提前解析参数:

    • 在application.properties中添加配置,让Tomcat在请求进入Servlet之前完成参数解析:
      server.tomcat.force-parse-parameters=true
      
      该配置可避免后续Spring MVC解析参数时出现异常。
  3. 优化Tomcat线程池配置:

    • 虽然不是直接诱因,但合理的线程池配置可避免高负载下的线程耗尽问题,参考配置:
      server.tomcat.max-threads=200
      server.tomcat.min-spare-threads=50
      

内容的提问来源于Stack Exchange,提问作者James Pizzurro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 00:10:27