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

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:

  1. 创建一个配置类,实现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"
        ));
    }
}
  1. 创建一个专门处理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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 00:30:55