Spring Boot中处理Tomcat请求解析失败问题
解决Spring Boot URL含非法字符时无法触发统一错误处理的问题
问题根源
当URL包含|这类违反RFC规范的非法字符时,Tomcat在请求解析阶段就会直接拒绝请求,此时请求还没到达Spring的DispatcherServlet,所以Spring的错误处理机制(ErrorController、@ExceptionHandler)根本不会被触发,直接返回Tomcat自带的400错误页面。
解决方案
方案1:调整Tomcat的非法字符允许规则(不推荐生产环境)
如果业务确实需要允许某些特殊字符,可通过配置放宽Tomcat的限制:
- 在
application.properties或application.yml中添加:
# 允许URL中包含的特殊字符,根据需求添加,比如|、\等 server.tomcat.relaxed-path-chars=| server.tomcat.relaxed-query-chars=|
这样Tomcat会允许这些字符进入请求解析,之后就能被Spring的错误处理机制捕获(如果后续业务逻辑抛出异常的话)。但注意:这会违反HTTP规范,可能带来安全风险,生产环境谨慎使用。
方案2:自定义Tomcat的错误页面,返回JSON格式
既然请求在Tomcat阶段就被拦截,直接配置Tomcat的错误页面,让它返回自定义JSON:
- 创建一个配置类,实现
WebServerFactoryCustomizer<TomcatServletWebServerFactory>:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.stereotype.Component; @Component public class TomcatErrorConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { // 针对400错误配置自定义响应 factory.addErrorPages(new org.springframework.boot.web.server.ErrorPage( org.springframework.http.HttpStatus.BAD_REQUEST, "/tomcat-error-handler" )); } }
- 创建一个专门处理Tomcat错误的Controller:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/tomcat-error-handler") public class TomcatErrorHandlerController { @GetMapping public ResponseEntity<Map<String, Object>> handleTomcatError() { Map<String, Object> errorResponse = new HashMap<>(); errorResponse.put("code", "INVALID_REQUEST"); errorResponse.put("message", "请求URL包含非法字符,违反HTTP规范"); errorResponse.put("status", HttpStatus.BAD_REQUEST.value()); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } }
这样当Tomcat拦截到非法字符的请求时,会转发到这个Controller,返回统一格式的JSON响应。
方案3:使用Spring Boot的全局错误页面配置(更简洁)
直接在application.properties中配置错误页面的转发路径,指向自定义的错误处理端点:
# 配置400错误的转发路径 server.error.path=/global-error-handler
然后确保你的自定义ErrorController(如果已经有)处理这个路径,或者新增一个:
import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @RestController public class GlobalErrorController implements ErrorController { @GetMapping("/global-error-handler") public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); Map<String, Object> errorResponse = new HashMap<>(); if (statusCode != null && statusCode == HttpStatus.BAD_REQUEST.value()) { errorResponse.put("code", "INVALID_REQUEST"); errorResponse.put("message", "请求URL包含非法字符,违反HTTP规范"); } else { errorResponse.put("code", "UNKNOWN_ERROR"); errorResponse.put("message", "服务器内部错误"); } errorResponse.put("status", statusCode != null ? statusCode : HttpStatus.INTERNAL_SERVER_ERROR.value()); return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(statusCode != null ? statusCode : 500)); } }
这个方案不需要自定义Tomcat配置,直接利用Spring Boot的错误转发机制,将Tomcat的错误请求转发到自定义ErrorController处理。
验证
用curl测试:
curl 'https://example.com/fail|no' -i
应该返回你定义的JSON格式错误响应,而不是Tomcat的默认页面。
内容的提问来源于stack exchange,提问作者ST-DDT
相关产品推荐
相关产品推荐

