異常: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 == '\t') {
            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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM