zoukankan      html  css  js  c++  java
  • 异常:Invalid character found in the request target. The valid characters are defined in RFC 3986

    一、背景

      事情是这样的,前几天做一个基本的数据库“增删改查”的需求,前端传参的方式是“JSON字符串”,后端接收到此参数后,使用阿里巴巴fastjson进行解析,然后入库。需求很简单吧,但是偏偏遇到问题了。

      我发现,JSON字符串里面无数组,纯粹的都是json结构的时候,即都是“{}”时,不会报错,传参入库没问题。但是只要传参的值里面有数组,即有“[]”的结构时,就报错。报错内容如下(我的tomcat版本是8.5.45):

    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:684)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
    

    二、原因

      tomcat的原因。 tomcat严格按照RFC规范进行范文解析,随着网络环境的变化,RFC规范也在不断的修改和升级中,发布了好多版本。而tomcat的不同版本中,采用的RFC规范的版本是不同的。所以你会在下文发现,有的低版本tomcat没有这个问题。

      tomcat自tomcat 8.0.35版本之后对URL参数做了比较规范的限制,必须遵循RFC 7230 and RFC 3986规范,对于非保留字字符(json格式的请求参数)必须做转义操作。例如:RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。

      Request For Comments(RFC),是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。目前RFC文件是由Internet Society(ISOC)赞助发行。基本的互联网通信协议都有在RFC文件内详细说明。RFC文件还额外加入许多在标准内的论题,例如对于互联网新开发的协议及发展中所有的记录。因此几乎所有的互联网标准都有收录在RFC文件之中——百度百科。

      附上网络大牛的源码分析:

    分析的是org.apache.tomcat.util.http.parser.HttpParser
    
    //tomcat 8.2.3 版本及 tomcat 7.0.82 ,都有如下代码,读取配置
    String prop = System.getProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow");
    if (prop != null) {
        for (int i = 0; i < prop.length(); i++) {
            char c = prop.charAt(i);
            if (c == '{' || c == '}' || c == '|') {
                REQUEST_TARGET_ALLOW[c] = true;
            } else {
                log.warn(sm.getString("httpparser.invalidRequestTargetCharacter",Character.valueOf(c)));
            }
        }
    }
    
    而tomcat 8.0.14 版本中并没有读取配置,对 | { } 的处理,而是默认为合法字符。
    static {
        for (int i = 0; i < 128; i++) {
            if (i < 32) {
                isToken[i] = false;
            } else if (i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                       i == ',' || i == ';' || i == ':' || i == '\' || i == '"' ||
                       i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                       i == '{' || i == '}' || i == ' ' || i == '	') {
                isToken[i] = false;
            } else {
                isToken[i] = true;
            }
            if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' ||i >= 'a' && i <= 'f') {
                isHex[i] = true;
            } else {
                isHex[i] = false;
            }
        }
    }
    可以看出在 8.0.x 左右的一些版本中,tomcat.util.http.parser.HttpParser. requestTargetAllow (下文方法三)这个配置是没有生效的,即| { } 这3个符号认为是合法的。

    三、解决

      注:我是使用“方法五”解决问题的,推荐“方法五”。

      方法一:换到低版本的Tomcat。

      方法二:在Catalina.properties中添加tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}这个东西明显是允许“|”和大括号的,但是我现在的问题是中括号。

      方法三:添加tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true这个是允许url中带有特殊字符的。试过了,也不好使。

      方法四:对传递的“JSON字符串”进行url编码后在传递,可以规避这个方括号。前端用“encodeURI(xxx)”方法编码,后端用“URLDecoder.decode(xxx, "utf-8")”解码即可。

      方法五:在tomcat目录的conf文件夹下,server.xml的Connector中添加了这个relaxedQueryChars="[,]"。

          注:

    1、如果还有其他特殊的字符串,也可以直接添加到这个属性里;

    2、如果你是springboot项目,可以在SpringBootApplication的的main方法中增加:System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow","[]");       

    参考

    1、https://blog.csdn.net/Hitler698/article/details/85720156

    2、https://my.oschina.net/pding/blog/1794176

    在全栈的道路上,积极向上、成熟稳重、谦虚好学、怀着炽热的心向前方的走得更远。
  • 相关阅读:
    [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)
    [学习笔记] CDQ分治&整体二分
    [日常] NOIp 2018 滚粗记
    [学习笔记] 模拟退火 (Simulated Annealing)
    [日常] NOIWC 2018爆零记
    [日常] PKUWC 2018爆零记
    [日常] 最近的一些破事w...
    [BZOJ 1877][SDOI2009]晨跑
    [COGS 2583]南极科考旅行
    [日常] NOIP 2017滚粗记
  • 原文地址:https://www.cnblogs.com/DDgougou/p/11668073.html
Copyright © 2011-2022 走看看