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

WebSphere中Spring Boot大Payload触发IllegalArgumentException问题排查

问题:Spring Boot 2.7.18部署在WebSphere 9上处理大Payload POST请求报错

异常现象

将Spring Boot 2.7.18应用部署在WebSphere Application Server 9上时,处理大Payload的POST请求会抛出如下异常:

java.lang.IllegalArgumentException: null
    at com.ibm.wsspi.webcontainer.util.RequestUtils.parseQueryString(RequestUtils.java:288)
    ...

小Payload请求可正常处理,大Payload则触发错误。

现有@InitBinder配置

@InitBinder
public void dataBinding(WebDataBinder binder) {
    binder.setAutoGrowCollectionLimit(4500);
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}

已设置集合上限为4500,小Payload可正常运行,但Payload增大后报错,堆栈跟踪显示错误发生在com.ibm.wsspi.webcontainer.util.RequestUtils.parseQueryString(RequestUtils.java:288)。

完整堆栈跟踪

java.lang.IllegalArgumentException: null
    at com.ibm.wsspi.webcontainer.util.RequestUtils.parseQueryString(RequestUtils.java:288)
    at com.ibm.wsspi.webcontainer.util.RequestUtils.parseQueryString(RequestUtils.java:108)
    at com.ibm.ws.webcontainer.servlet.RequestUtils.parsePostData(RequestUtils.java:384)
    at com.ibm.ws.webcontainer.servlet.RequestUtils.parsePostDataLong(RequestUtils.java:396)
    at com.ibm.ws.webcontainer.srt.SRTServletRequest.parseParameters(SRTServletRequest.java:2398)
    at com.ibm.ws.webcontainer.srt.SRTServletRequest.getParameterMap(SRTServletRequest.java:3042)
    at javax.servlet.ServletRequestWrapper.getParameterMap(ServletRequestWrapper.java:203)
    at org.springframework.security.web.firewall.StrictHttpFirewall$StrictFirewalledRequest.getParameterMap(StrictHttpFirewall.java:778)
    at javax.servlet.ServletRequestWrapper.getParameterMap(ServletRequestWrapper.java:203)
    at javax.servlet.ServletRequestWrapper.getParameterMap(ServletRequestWrapper.java:203)
    at javax.servlet.ServletRequestWrapper.getParameterMap(ServletRequestWrapper.java:203)
    at com.vayana.boot.infra.web.security.filter.XSSRequestWrapper.<init>(XSSRequestWrapper.java:34)
    at com.vayana.boot.infra.web.security.filter.SecurityFilter.doFilter(SecurityFilter.java:84)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:147)
    at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:125)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:223)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:132)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:126)
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.access$000(ErrorPageFilter.java:64)
    at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:101)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:119)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:979)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1119)
    at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:82)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:966)
    at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1817)
    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:382)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:465)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:532)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:318)
    at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:88)
    at com.ibm.ws.ssl.channel.impl.SSLReadServiceContext$SSLReadCompletedCallback.complete(SSLReadServiceContext.java:1833)
    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1909)

已尝试的步骤

  • 增大binder.setAutoGrowCollectionLimit值
  • 测试小Payload验证功能正常

观察结果

  • 小Payload(如600条数据)可正常处理
  • Payload超过一定大小就触发错误

疑问

  1. 是否需要调整WebSphere的特定配置或上限以处理大Payload?
  2. 该问题是否与WebSphere的请求参数或查询字符串大小限制有关?若有关,如何修改相关配置?
  3. 在WebSphere或Spring Boot中还有哪些设置或方法可有效处理大Payload?
  4. 生产环境中的Web Application Firewall(WAF)对请求体长度有严格限制,是否会导致该问题?若会,如何配置Spring Boot以在不触发WAF限制的前提下有效处理大Payload?

补充说明:生产环境中的WAF对请求体长度有严格限制,超过限制的请求会被拒绝,影响应用功能,是否有通过Spring Boot处理该问题的简便方法?


解决方案

1. 调整WebSphere的参数解析限制

从堆栈看,错误发生在WebSphere解析POST数据为参数的阶段,这和WebSphere的请求参数最大数量限制有关,而非单纯的请求体大小。WebSphere默认限制单个请求的参数数量为1000,当大Payload包含的参数(比如表单字段、数组元素)超过这个值时,就会触发IllegalArgumentException。

修改WebSphere配置步骤:

  • 登录WebSphere管理控制台,进入服务器 > 服务器类型 > WebSphere应用服务器 > 你的服务器名称
  • 点击Web容器设置 > Web容器
  • 展开自定义属性,添加或修改以下属性:
    • com.ibm.ws.webcontainer.maxParamCount:设置为足够大的值(比如5000,对应你的集合上限4500)
    • com.ibm.ws.webcontainer.postBufferSize:如果请求体过大,可适当增大这个值(单位为字节,比如10485760即10MB)
  • 保存配置并重启服务器

2. 优化Spring Boot参数绑定配置

虽然你已经设置了autoGrowCollectionLimit,但还可以补充以下配置:

  • 在application.properties中添加:
    spring.mvc.format.date=dd-MM-yyyy
    spring.mvc.format.date-time=dd-MM-yyyy HH:mm:ss
    
    替代@InitBinder中的日期编辑器配置,避免重复设置,同时确保全局生效。
  • 如果使用@RequestBody接收JSON格式的Payload,确保启用Jackson的大集合支持:
    spring.jackson.deserialization.accept-single-value-as-array=true
    

3. 避免提前解析参数(针对自定义Filter)

从堆栈看,错误发生在XSSRequestWrapper初始化时调用getParameterMap(),这会触发WebSphere提前解析POST参数。如果你的XSS过滤不需要处理请求参数,可修改XSSRequestWrapper,延迟参数解析,或者只针对需要的参数进行处理,避免一次性解析所有参数。

4. 处理WAF请求体限制的方案

如果WAF限制了请求体大小,可通过以下方式优化:

  • 分批次提交数据:将大Payload拆分为多个小请求,前端分页提交,后端批量处理。
  • 使用流式处理:在Spring Boot中使用InputStream直接读取请求体,避免一次性加载到内存,同时配合Jackson的流式解析逐行处理数据:
    @PostMapping("/batch")
    public ResponseEntity<Void> processBatch(HttpServletRequest request) throws IOException {
        try (JsonParser parser = new JsonFactory().createParser(request.getInputStream())) {
            parser.nextToken(); // 跳过数组开始标记
            while (parser.nextToken() == JsonToken.START_OBJECT) {
                YourEntity entity = parser.readValueAs(YourEntity.class);
                // 处理单个实体逻辑
            }
        }
        return ResponseEntity.ok().build();
    }
    
  • 压缩请求体:前端对请求体进行Gzip压缩,后端启用Spring Boot的压缩支持:
    server.compression.enabled=true
    server.compression.mime-types=application/json
    server.compression.min-response-size=1024
    
    同时确认WAF支持解压Gzip格式的请求。

内容的提问来源于stack exchange,提问作者Kundan Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 18:54:49