一、问题错误
最近遇到客户端说接口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