IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    诺多发表于 2024-10-11 23:00:34
    love 0

    最近在半夜升级一套基于SpringBoot开发的Feedbcak系统时,遇到了意料之外的状况。本来预想可能会有一些业务参数兼容性问题,结果这个问题没出现,却出现大量的的Tomcat报错,请求没有进入业务代码,直接在Tomcat层面400了。

    症状

    具体的异常如下:

    java.lang.IllegalArgumentException: Invalid character found in the 
    request target [/feedback?xxx=asdasd&yyy=abc|dedg|hijk]. 
    The valid characters are defined in RFC 7230 and RFC 3986
    

    为了避免不必要的麻烦,上面的异常堆栈删改了一些无关的内容。java.lang.IllegalArgumentException,这一看就是参数中出现不该出现的字符了,赶紧把参数复制下来,在本地IDE环境和测试Docker环境验证,结果都没有复现这个问题,请求可以正常进入业务代码。检查了Tomcat版本,本地、测试环境和线上全都是9.0.39,这就奇了怪了!

    2024-10-11 00:02:03,165[][main]INFO(DirectJDKLog.javalog173)-Initializing ProtocolHandler ["http-nio-0.0.0.0-8080"]
    2024-10-11 00:02:03,166[][main]INFO(DirectJDKLog.javalog173)-Starting service [Tomcat]
    2024-10-11 00:02:03,166[][main]INFO(DirectJDKLog.javalog173)-Starting Servlet engine: [Apache Tomcat/9.0.39]
    

    结合The valid characters are defined in RFC 7230 and RFC 3986这段提示,一搜就知道了原因,原来是tomcat8.0以上版本遵从RFC规范添加了对Url的特殊字符的限制,url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~四个特殊字符以及保留字符( ! * ’ ( ) ; : @ & = + $ , / ? # [ ] ) 等各种特殊字符均不被允许,否则就会报上面的错误。

    仔细一看,请求的参数中果然有受限制的字符|,即:yyy=abc|dedg|hijk。

    解决方法

    知道了原因,那就好办了,直接问大模型AI如何解决吧(相比于搜索引擎哼哧哼哧漫无边际的找,AI确实在编程辅助方面有很大作用)。

    马上就有了答案,在不降低Tomcat版本的前提下,Tomcat提供了接触限值的方法,分别支持对请求参数和路径设置例外字符的能力。在SpringBoot项目中,有两种方法进行设置。

    1️⃣ 配置文件设置

    直接在application.properties或application.yml设置。

    在application.properties中

    server.tomcat.relaxed-path-chars=[,],|,
    server.tomcat.relaxed-query-chars=[,],{,},
    

    在application.yml中,你可以这样设置:

    server:
      tomcat:
        relaxed-path-chars: "[,],|,"
        relaxed-query-chars: "[,],{,},"
    

    2️⃣ 编码方式设置

    在项目中创建一个TomcatServletWebServerFactory的Bean,并添加自定义的Connector配置。

    @Configuration
    public class TomcatConfig {
        @Bean
        public ConfigurableServletWebServerFactory webServerFactory() {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
            factory.addConnectorCustomizers(connector -> {
                connector.setProperty("relaxedPathChars", "|{}[]");
                connector.setProperty("relaxedQueryChars", "|{}[]");
            });
            return factory;
        }
    }
    

    两种方法任选一种即可,笔者照葫芦画瓢,直接在配置文件中增加一条配置:

    server.tomcat.relaxed-path-chars=|
    

    重启应用后,400错误果然消失了,问题成功解决。此时看看时间,已然是凌晨2点多😂

    尾巴

    问题虽然解决了,但还是有一个问题笔者没有找到原因,那就是同一个Docker镜像,跑在测试机群上可以正常处理特殊字符,跑在线上就GG了。照理说都已经用Docker镜像了,同样版本的Tomcat为何会有不一样的表现?这真是个大大的懵字。

    如果有大牛知道原因,还望不吝赐教!

    原创不易,如果觉得此文对你有帮助,不妨点赞+收藏+关注,你的鼓励是我持续创作的动力!

    高等精灵实验室



沪ICP备19023445号-2号
友情链接