【前情提要】最近开发过程中遇到一个Tomcat
中IllegalArgumentException
的报错,所以在这里记录一下。
壹、错误现象
在用Get请求是当URL中包含特殊字符,比如:<
、>
、(
、)
、{
、}
、|
等时,Tomcat会报出以下错误:
1 | java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 |
贰、故障原因
因为Tomcat严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。传入的参数中有”{“不在RFC3986中的保留字段中,所以会报参数异常错。而且这个错误你在应用中处理不到,因为根本都还没有进入应用,在Tomcat中就已经报错了,而且就连你在Tomcat中配置错误页面也没有用。
叁、解决方案
3.1、定义requestTargetAllow属性
Tomcat 7.0.76, 8.0.42, 8.5.12 这些版本之后可以定义requestTargetAllow 属性来允许禁止的字符。在tomcat的 catalina.properties文件中添加这一句:
1 | tomcat.util.http.parser.HttpParser.requestTargetAllow=|{} |
3.2、修复server.xml配置文件
如果某些版本的Tomcat已经参照3.1
中的方法修改之后,还是不生效的话。从官网的文档中我们可以查看到如下提示:tomcat.util.http.parser.HttpParser. requestTargetAllow(This system property is deprecated. Use the relaxedPathChars and relaxedQueryChars attributes of the Connector instead)
所有我们在Tomcat配置文件中:$CATALINA_HOME/conf/server.xml添加relaxedQueryChars
属性添加到Connector元素:
1 | <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" relaxedQueryChars="[]|{}^\`"<>" redirectPort="8443" /> |
3.3、Springboot修改方法
在SpringBootApplication的的main方法中增加
1 | System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow","|{}"); |
另外在Springboot 2.0 之后的版本,可以自定义WebServerFactoryCustomizer
,添加特殊字符的支持:
1 | import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; |