天天看點

Tomcat 8 Invalid character found in the request target. The valid characters are defined in RFC 3986

終極解決方案:

Invalid character found in the request target. The valid characters are defined in RFC 3986

25-Aug-2018 11:27:27.086 資訊 [http-nio-8087-exec-5] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
 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)
           

從錯誤日志中看到

Error parsing HTTP request header

負責解析http請求的是

org.apache.tomcat.util.http.parser.HttpParser

,它對請求對URL中對字元做了限制,具體代碼如下:

IS_NOT_REQUEST_TARGET[]中定義了一堆not request target

if(IS_CONTROL[i] || i > 127 || i == 32 || i == 34 || i == 35 || i == 60 || i == 62 || i == 92 || i == 94 || i == 96 || i == 123 || i == 124 || i == 125) {
                IS_NOT_REQUEST_TARGET[i] = true;
            }
           

轉換過來就是以下字元(對應10進制ASCII),也就是URL中不能包含的特殊字元:

  • 鍵盤上那些控制鍵:(<32或者=127)

  • 非英文字元(>127)

  • 空格(32)

  • 雙引号(34)

  • #(35)

  • <(60)

  • >(62)

  • 反斜杠(92)

  • ^(94)

  • TAB上面那個鍵,~(96)

  • {(123)

  • }(124)

  • |(125)

我碰到這個問題也搗弄了半天,參照其他的各種解決方案都不行。并且我是使用了多種特殊字元,運用單一某種方案還不能完全奏效。下面是經過實踐的解決方案,請按順序讀完。

解決辦法(親測)

在conf/catalina.properties中最後添加2行:

tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
           

該方式,在所有Tomcat版本均适用。

解析:在執行請求時,碰到該沒問題的,大多是在URL中傳輸Json等。尤其是用浏覽器位址輸入的URL死活不能包含有任何特殊字元。否則會傳回400 狀态碼。

首先:不推薦降低tomcat版本,這等于掩耳盜鈴,絕對得不償失。

Tomcat在 7.0.73, 8.0.39, 8.5.7 版本後,在http解析時做了嚴格限制。

RFC3986文檔規定,請求的Url中隻允許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字元以及所有保留字元。

如果要使用這些特殊字元,并不是絕對不可以。Tomcat做了限制的同時,也提供了相關配置。給出的解決方案第一行

requestTargetAllow

,指定了允許的特殊字元,在等号後面配|{}就行了。

如果你僅需要使用這三個字元,配置到此就OK了。重新開機tomcat,rebuild工程再啟動,就能正常使用了。

不幸的是,

requestTargetAllow

隻能配置|、{、} 允許這三個字元,對于其他的(例如" < > [ \ ] ^ ` { | } .),在請求時,仍然攔截,如果使用了|{}之外的其他字元那怎麼辦呢?那就還需要如下配置。

在conf/server.xml中的<Connector>節點中,添加2個屬性:

relaxedPathChars="|{}[],"
relaxedQueryChars="|{}[],"
           

這2個屬性,可以接收任意特殊字元的組合,根據需要可以自行增減。

與此相關的文檔說明:

Tomcat 8 Invalid character found in the request target. The valid characters are defined in RFC 3986

文檔位址:

https://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html
Tomcat 8 Invalid character found in the request target. The valid characters are defined in RFC 3986
https://tomcat.apache.org/tomcat-8.5-doc/config/http.html
Tomcat 8 Invalid character found in the request target. The valid characters are defined in RFC 3986
http://tomcat.apache.org/tomcat-7.0-doc/changelog.html

另一種方式,就是發請求前,進行URLEncoder.encode(requestURI,"UTF-8");此方法适用于 執行送出請求的是ajax或其他用戶端程式(可以發出http請求的程式設計語言,都有encode()相關支援)。

然後在背景接收請求後decode()

String params = request.getParameter(PARAMS);

params = URLDecoder.decode(params,"UTF-8");