一、SpringBoot 項目,使用自帶tomcat
1、問題描述
接收 application/x-www-form-urlencoded Post
參數 data={"data":[{"id_dev":"CSB000001","state":"online","on_ts":1526004805}, {"id_dev":"CSB000001","state":"online","on_ts":1526004805,"off_ts":1526004810}]}
報錯:
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
2、原因分析
導致上述問題是因為tomcat自8.5.x系列的:8.5.12 之后版本、8.0.x系列的:8.0.42 之后版本、7.0.x系列的:7.0.76 之后版本對URL參數做了比較規范的限制,必須遵循RFC 7230 and RFC 3986規范,對於非保留字字符(json格式的請求參數)必須做轉義操作,否則會拋出Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986錯誤信息。就是嚴格按照 RFC 3986規范進行訪問解析,而 RFC 3986規范定義了Url中只允許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字符以及所有保留字符(RFC3986中指定了以下字符為保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。
3、解決方法
1)降低tomcat版本,不推薦
2)在SpringBoot工程中增加一個tomcat 配置,配置文件代碼如下
@Configuration public class TomcatConfigurer { @Bean public TomcatServletWebServerFactory webServerFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addConnectorCustomizers((Connector connector) -> { connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}"); connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}"); }); return factory; } }
參考:https://www.jianshu.com/p/75eec24321e7
二、SpringBoot 項目,部署獨立tomcat
1、同樣問題
2、解決方法
參考:https://developer.aliyun.com/article/641394
在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個屬性,可以接收任意特殊字符的組合,根據需要可以自行增減。
參考文檔:https://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html