如何在底层servlet容器处理前避免Spring Boot请求目标无效字符报错
问题复现
你遇到的异常栈如下:
java.lang.IllegalArgumentException: Invalid character found in the request target [/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=HelloThinkPHP21 ]. The valid characters are defined in RFC 7230 and RFC 3986 at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:494) ~[tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:269) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.54.jar:9.0.54] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.54.jar:9.0.54] at java.lang.Thread.run(Thread.java:831) [?:?]
根因说明
Tomcat 自 7.0.73、8.0.39、8.5.7 版本开始,默认严格执行 RFC 7230、RFC 3986 规范,对请求URL中的非允许字符(包括反斜杠\、中括号[]、大括号{}、竖线|等)会直接在请求解析阶段抛出异常,此时请求还未进入Spring MVC的业务处理逻辑,属于Servlet容器(Tomcat)层面的拦截。
规避方案
方案1:配置Tomcat放宽字符校验(适用允许对应特殊字符入站的场景)
方式A:通过Spring Boot配置文件直接配置(Spring Boot 2.2+ 版本支持)
在application.properties中添加如下配置:
# 允许URL中出现的特殊字符,根据实际需要添加 server.tomcat.relaxed-path-chars=[]|\\^`{} server.tomcat.relaxed-query-chars=[]|\\^`{}
如果是application.yml,配置如下:
server: tomcat: relaxed-path-chars: "[]|\\^`{}" relaxed-query-chars: "[]|\\^`{}"
方式B:自定义Tomcat连接器配置(兼容所有Spring Boot版本)
新增Tomcat配置类,手动修改连接器属性:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.apache.catalina.connector.Connector; @Configuration public class TomcatConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> webServerFactoryCustomizer() { return factory -> factory.addConnectorCustomizers((Connector connector) -> { connector.setAttribute("relaxedPathChars", "[]|\\^`{}"); connector.setAttribute("relaxedQueryChars", "[]|\\^`{}"); }); } }
方案2:前置代理层拦截非法请求(适用需要在Servlet容器处理前拦截的场景)
如果需要完全在Tomcat处理请求前就规避该问题,可以在Tomcat上层部署Nginx等反向代理服务,在代理层配置规则:直接拦截携带非法字符的异常请求,仅放行符合规范的请求到后端Tomcat服务,从根源上避免异常请求进入Tomcat处理流程。
方案3:前端请求编码(最符合规范的方案)
要求前端发送请求时,对URL路径和查询参数中的特殊字符做URL编码,特殊字符会被转为%XX格式的编码串,完全符合RFC规范,不会触发Tomcat拦截。
内容的提问来源于stack exchange,提问作者Rpj
相关产品推荐
相关产品推荐

