为何相同Payload的POST请求,无尾斜杠URL返回HTTP 400错误?
控制器代码
@RestController(value="/api") public class ApiController{ @PostMapping("/post") @ResponseStatus(HttpStatus.OK) public ResponseObject postMethod(RequestObject obj){ //service calls } }
现象描述
- 调用带尾斜杠的端点:
POST
http://localhost:8989/api/post/
携带Payload时,请求可成功命中控制器方法。 - 调用无尾斜杠的端点:
POST
http://localhost:8989/api/post
携带完全相同的Payload时,服务器返回400错误,响应内容如下:
{ "timestamp": "2022-11-29T11:23:36.153+03:00", "status": 400, "error": "Bad Request", "message": "", "path": "/api/post" }
错误日志追踪
[2022-11-29 11:23:36,153] [CID:] [RID:] [http-nio-8989-exec-1] TRACE --- DispatcherServlet : "ERROR" dispatch for POST "/error", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
[2022-11-29 11:23:36,153] [CID:] [RID:] [http-nio-8989-exec-1] TRACE --- RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
[2022-11-29 11:23:36,153] [CID:] [RID:] [http-nio-8989-exec-1] TRACE --- HandlerMethod : Arguments: [SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ org.apache.catalina.core.ApplicationHttpRequest@3660b306]]]
[2022-11-29 11:23:36,153] [CID:] [RID:] [http-nio-8989-exec-1] DEBUG --- HttpEntityMethodProcessor : Using 'application/json', given [application/json] and supported [application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/+xml;charset=UTF-8, application/json, application/+json, application/x-jackson-smile]
[2022-11-29 11:23:36,154] [CID:] [RID:] [http-nio-8989-exec-1] TRACE --- HttpEntityMethodProcessor : Writing [{timestamp=Tue Nov 29 11:23:36 TRT 2022, status=400, error=Bad Request, message=, path=/api/loanaccount/cancelLimitTransaction}]
[2022-11-29 11:23:36,154] [CID:] [RID:] [http-nio-8989-exec-1] TRACE --- DispatcherServlet : No view rendering, null ModelAndView returned.
排查方向
- 检查Spring MVC路径匹配策略:
Spring Boot的spring.mvc.pathmatch.matching-strategy配置决定路径匹配规则,旧的ANT_PATH_MATCHER默认忽略尾斜杠差异,新的PATH_PATTERN_MATCHER会严格区分。可尝试将配置改为ANT_PATH_MATCHER验证是否解决问题。 - 排查重复路由映射:
检查项目中是否存在其他控制器或方法映射了/api/post(无尾斜杠),且该方法参数接收逻辑有问题,导致请求被错误路由后无法解析Payload返回400。 - 开启路由匹配详细日志:
将org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping的日志级别设为DEBUG,查看请求到达时Spring尝试匹配的所有路由,确认无尾斜杠请求是否匹配到错误处理器,或根本未匹配到目标方法。 - 检查Tomcat防火墙配置:
日志中出现FirewalledRequest,Tomcat的HttpFirewall可能对请求路径做了修改或拦截。可尝试关闭Tomcat防火墙(配置server.tomcat.http-firewall.allow-back-slash=true等参数),或调整规则允许无尾斜杠请求。 - 验证请求是否被重定向:
部分场景下,带尾斜杠和不带尾斜杠的请求会触发3xx重定向,POST请求重定向后可能转为GET,导致Payload丢失返回400。用请求工具(如Postman)查看完整响应链,确认是否存在重定向。 - 检查RequestObject反序列化异常:
虽然Payload相同,但如果请求未进入目标方法,可能是路由错误导致请求被其他处理器接收,触发反序列化失败。可在postMethod开头添加日志,确认无尾斜杠请求是否真的未进入该方法;同时检查全局异常处理器是否捕获了反序列化异常但未输出详细信息。
内容的提问来源于stack exchange,提问作者user7514788

