问题描述:
之前使用的是Springboot2.0.0版本没有什么问题的,然后因为使用elasticsearch7.8.0版本后要把Springboot升级到2.3.1后就出现这个问题(其实这个问题应该在Springboot2.2.x以上都会出现了,只是我一下升级到2.3.1版本)
elasticsearch的部分请看链接:https://blog.csdn.net/qq_38680405/article/details/107225724
前端的GET请求url中带有路径参数,这个参数中有[]或者/这个特殊字符,前端已经转移成了%2F,后端用的是springboot,并没有收到这个请求,直接返回了400的错误。(注意是后端根本没有收到请求就直接报400了)
原因是:
这个问题是由于Tomcat的新版本中增加了一个新特性,就是严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。
解决方案:
① 可以客户端请求时URL encode处理特殊字段
②新创建一个类即可
@Configuration
public class TomcatConfig {
@Bean
public TomcatServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
connector.setProperty("rejectIllegalHeader", "false");
}
});
return factory;
}
}
关于这个配置的解释参考:Tomcat-9.0-doc
rejectIllegalHeader
If an HTTP request is received that contains an illegal header name or value (e.g. the header name is not a token) this setting determines if the request will be rejected with a 400 response (true) or if the illegal header be ignored (false). The default value is true which will cause the request to be rejected.
这样配置后(1.x的配置类似),大部分URI和Header都可以兼容,但是正如文档里所说的,rejectIllegalHeader会导致非法的header忽略,即header信息将不会被服务器接收。
所以一旦Header里面有非法字符,对应的Header项将被忽略,服务器不会报400,但会跳过这个header项,比如升级过程中我们发现有API在header里传输中文,导致服务启报错,加了rejectIllegalHeader=false后,不报400,但程序找不到对应的Header,最后不得不删除这些不规范的header。
③更改springboot内置的Tomcat版本(未测试,如果您尝试,请在评论区发表您的结果,以供大家学习)
步骤1. 查看使用的org.springframework.boot版本
版本为2.3.1
打开本地maven repository目录下的spring-boot-dependencies文件:
D:\repository\org\springframework\boot\spring-boot-dependencies\2.3.1.RELEASE\spring-boot-dependencies-2.3.1.RELEASE.pom
可以在标签下面找到<tomcat.version>9.0.36</tomcat.version>
修改此处tomcat版本恢复到低版本,例如:8.0.32版本即可修改URL传特殊字符问题。此方法本人未尝试,本人通过方法已经解决问题,在此仅提供多一个思路给码友。