一、背景
事情是这样的,前几天做一个基本的数据库“增删改查”的需求,前端传参的方式是“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
3、http://www.bubuko.com/infodetail-3238579.html
原文地址:https://www.cnblogs.com/JoePotter/p/11773797.html