原文地址:https://maiyikai.github.io/2020/02/27/1582786564/
Spring Boot 项目中都会嵌入 Tomcat, 在不同版本的 Spring Boot 下,也会嵌入不同版本的 Tomcat 。Tomcat 作用和用途这里就不用再赘述了…
在项目的迁移过程中,由原先的 Servlet 项目 改造成了 Sprong Boot 项目,导致了一系列的问题,目前让我觉得可以记录的就是当前的这个 Tomcat 的问题了。因为在正常情况下不会涉及到这种问题,但是进行服务版本改造的时候应该会出现类似的问题。
抛转引玉
访问地址:http://addression/ServerName/Web.jsp?json={“balibali”…}
访问后端时报错: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
浏览器返回的结果是:400
一开始,还不知道是什么原因,因为我用 PostMan 访问是正常的,但是用浏览器就出问题。Servlet 服务中是可以正常访问的,但是在 SpringBoot 项目中就不行了。
于是乎开始针对这个这个问题排查,奇怪的是这个异常信息在多次访问的之后,只打印一次,一开始还不重视它,但是整个日志就没有其他的异常信息
网络搜寻
一直找不到原因,于是就尝试使用这个异常去查,结果知道了原因:说是因为 Tomcat 对 URL 字符作了限制,而我地址中就存在了这些被限制的字符,于是乎对访问地址进行多次测试:
- http://addression/ServerName/Web.jsp --> 没有报错
- http://addression/ServerName/Web.jsp?json=balabala…—> 没有报错
- http://addression/ServerName/Web.jsp?json={}–> 400
- http://addression/ServerName/Web.jsp?json=%7B %7D–> 正常(%7B %7D分别对应的是字符 { } )
综上可知,是参数 json 赋值为一个对象时报错误,但是步骤 3 和 步骤 4 在某种意义上是一样的,因为在浏览器地址栏输入步骤 4 ,回车之后你看到的就是步骤 3 的地址…
但是步骤 4 是正常的,步骤 3 是错的…
百度与谷歌
知道了是 Tomcat 对 URL 的字符限制,就想先试试更改一下 Tomcat 的配置,网上找了一堆的教程
Tomcat 系列
- 更改 Tomcat 版本
- 配置tomcat支持|{}等字符的方法是:在 catalina.properties中添加 tomcat.util.http.parser.HttpParser.requestTargetAllow=|{} 但是只支持7.0.76, 8.0.42, 8.5.12 之后的版本
看到了这个答案,感觉有戏,结果才想起来, SpringBoot 项目中的 Tomcat 是内嵌的啊,难不成要重新引入一个?未免太过麻烦,而且后期还不好维护…等等一堆问题,怎么办呢?应该还有 Spring Boot 解决方案,再找找…
SpringBoot 系列
因为是公司项目,所以选用的 SpringBoot 版本一般不会改变,这里使用是 1.5.6 版本的。
- SpringBoot 2.* 版本解决方案-工厂配置(未验证)
//引入这个配置
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> connector.setProperty("relaxedQueryChars", "|{}[]\\"));
return factory;
}
- SpringBoot 1.* 版本解决方案-工厂配置(未生效)
/**
* 解决异常信息:
* java.lang.IllegalArgumentException:
* Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
* @return
*/
@Bean
public EmbeddedServletContainerCustomizer webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setProperty("relaxedQueryChars", "|{}[]");
}
});
return factory;
}
- SpringBoot 1.* 版本解决方案-工厂配置(已有的配置–未生效)
@Component
public class PortalTomcatWebServerCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if(container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) container;
containerFactory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setAttribute("relaxedQueryChars", "[]|{}:,^\`"<>");
connector.setAttribute("relaxedPathChars", "[]|:,");
}
});
}
}
}
- SpringBoot 1.* 版本解决方案-属性配置(生效)
@Configuration
public class RfcConfig {
@Bean
public Integer setRfc()
{
// 指定jre系统属性,允许特殊符号, 如{} 做入参,其他符号按需添加。见 tomcat的HttpParser源码。
System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow", "|{}");
return 0;
}
}
根据查询结果尝试,在当前项目中只有第 4 个方案是有用的…
总结
根据网络查询的结果不一定是可行的,需要多次查找,多次尝试,才能知道哪些是可行的。
针对于技术型问题,谷歌查询的比较精准
来源:CSDN
作者:maiyikai
链接:https://blog.csdn.net/maiyikai/article/details/104550382