案发现场
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:479)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:687)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
原因分析
- Tomcat8.5.30之后的版本,参数中有特殊字符(如:
| { }
)的话会报错,直接返回400 - RFC(Request For Comments)规范
- RFC 3986 规范定义了URL中只允许包含英文字母
a-zA-Z
、数字0-9
、-_.~
4个特殊字符以及所有保留字符 - RFC 3986 中指定了以下字符为保留字符:
! * ’ ( ) ; : @ & = + $ , / ? # [ ]
- URL中不允许有
| { }
等特殊字符
- RFC 3986 规范定义了URL中只允许包含英文字母
但在实际生产中还是有些URL可能会携带一些特殊字符,特别是|
还是较为常见的。
在 Tomcat 升级到 7 以后,对URL字符的检查都变严格了,如果出现这类字符,Tomcat 将直接返回 400 状态码。
解决方案
Spring Boot 项目
@Configration
public class EmbeddedTomcatConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(connector -> connector.setAttribute("relaxedQueryChars", "[]"));
}
}
Tomcat Server
server.xml
中修改Connector
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
relaxedQueryChars="[]|{}^\`"<>"
redirectPort="8443" />