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 字符作了限制,而我地址中就存在了这些被限制的字符,于是乎对访问地址进行多次测试:

  1. http://addression/ServerName/Web.jsp –> 没有报错
  2. http://addression/ServerName/Web.jsp?json=balabala...---> 没有报错
  3. http://addression/ServerName/Web.jsp?json={}--> 400
  4. http://addression/ServerName/Web.jsp?json=%7B %7D–> 正常(%7B %7D分别对应的是字符 { } )

综上可知,是参数 json 赋值为一个对象时报错误,但是步骤 3 和 步骤 4 在某种意义上是一样的,因为在浏览器地址栏输入步骤 4 ,回车之后你看到的就是步骤 3 的地址…
但是步骤 4 是正常的,步骤 3 是错的…

百度与谷歌

知道了是 Tomcat 对 URL 的字符限制,就想先试试更改一下 Tomcat 的配置,网上找了一堆的教程

Tomcat 系列
  1. 更改 Tomcat 版本
  2. 配置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 版本的。

  1. SpringBoot 2.* 版本解决方案-工厂配置(未验证)

    1
    2
    3
    4
    5
    6
    7
    //引入这个配置
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> connector.setProperty("relaxedQueryChars", "|{}[]\\"));
    return factory;
    }
  2. SpringBoot 1.* 版本解决方案-工厂配置(未生效)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * 解决异常信息:
    * 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;
    }
  3. SpringBoot 1.* 版本解决方案-工厂配置(已有的配置–未生效)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @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", "[]|:,");
    }
    });
    }
    }
    }
  4. SpringBoot 1.* 版本解决方案-属性配置(生效)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Configuration
    public class RfcConfig {
    @Bean
    public Integer setRfc()
    {
    // 指定jre系统属性,允许特殊符号, 如{} 做入参,其他符号按需添加。见 tomcat的HttpParser源码。
    System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow", "|{}");
    return 0;
    }
    }

根据查询结果尝试,在当前项目中只有第 4 个方案是有用的…

总结

根据网络查询的结果不一定是可行的,需要多次查找,多次尝试,才能知道哪些是可行的。
针对于技术型问题,谷歌查询的比较精准

最后更新: 2020年04月07日 22:29

原始链接: https://maiyikai.github.io/2020/02/27/1582786564/

× ~谢谢大爷~
打赏二维码