一、問題錯誤
最近遇到客戶端說接口get請求,全部400錯誤,無法請求,剛開始以爲是服務器對請求進行攔截了,但是訪問主頁面是正常的,也是get請求,那麼可能就是tomcat
的問題了,想到tomcat8
的原因,會不會是請求參數的問題,後來url請求中包含{}[]
特殊字符的都報錯,是因爲Tomcat在 7.0.73
, 8.0.39
, 8.5.7
版本後,在http解析時做了嚴格限制。
tomcat8正常訪問:
後臺報錯原因:
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
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:745)
前臺報錯:
http://192.168.2.25:8080/hg/check/list?data={"userid":"6"}
Failed to load resource: the server responded with a status of 400 (Bad Request)
二、問題分析
在使用tomcat8中,我們可以看到錯誤java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
,也就是說我們的請求中包含無效的字符,由RFC規範可以得知,url中只允許包含英文字母(a-zA-Z)
、數字(0-9)
、-_.~
四個特殊字符由於我們請求中包含{}
字符串,所以tomcat報錯。
三、問題解決
1、不使用特殊字符:使用其他的常用字符或數字,但是對於一些特定的參數,是需要進行傳入特殊字符的——(不建議使用)
2、對請求URL編碼解碼:URLEncoder.encode(str,"UTF-8");
、URLDecoder.decode(str,"UTF-8");
,這種方法對於單一的請求還是可以的,或者在項目結構開始時,統一使用這種方式(可以使用)
3、配置Tomcat對特殊字符的支持:統一配置tomcat配置文件,在所有Tomcat版本均適用。(推薦使用)
我們在conf/catalina.properties
中最後添加2行,(親測有效)
tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
雖然Tomcat做了限制的同時,也提供了相關配置。給出的解決方案第一行requestTargetAllow
,指定了允許的特殊字符,在等號後面配|{}
就行了。
如果你只是需要使用這三個字符的話,使用上面的配置就可以使用了,重啓tomcat,啓動項目,就能正常使用了。
訪問成功:
但是由於項目經常會傳遞數組類型的數據,或者其他特殊字符串類型,但是requestTargetAllow
只能配置|{}
允許這三個字符,如果想要使用除了|{}
這三個字符以外其他的(< > [ \ ] ^ ` { | } .
)的字符串,我們需要以下配置:
在conf/server.xml
中的<Connector>
節點中,添加2個屬性:
relaxedPathChars="|{}[],"
relaxedQueryChars="|{}[],"
完整版:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
useBodyEncodingForURI="true"
relaxedPathChars="|{}[],"
relaxedQueryChars="|{}[],"
/>
添加了這2個屬性,重啓tomcat後,訪問項目時,我們就可以使用任意特殊字符,方便快捷,而且不需要大規模的進行改動。
tomcat 文檔地址:https://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html