在使用FastJson做HttpMessageConverter的时候,如果客户端(嵌入式设备),传来非法字符(出现问题的是编码错误的表情包,本应使用4个字节的UTF-8编码,客户端将其编码为两个3字节的字符,Java中无法识别),在将ResponseBody以字符串形式获取时(@requestbody String data)会报Resolved exception caused by handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing。
详细错误信息如下:
Error parsing HTTP request header
java.io.EOFException: null
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1289) ~[tomcat-embed-core-8.5.35.jar:8.5.35]
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1223) ~[tomcat-embed-core-8.5.35.jar:8.5.35]
at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:729) ~[tomcat-embed-core-8.5.35.jar:8.5.35]
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:368) ~[tomcat-embed-core-8.5.35.jar:8.5.35]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684) ~[tomcat-embed-core-8.5.35.jar:8.5.35]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
使用的依赖版本为Spring boot 1.5.18,FastJson 1.2.54
经过我的测试,这个问题是必现的,测试用例如下:
private static byte[] bytes = {
(byte) 0x7B, (byte) 0x22, (byte) 0x6E, (byte) 0x61, (byte) 0x6D,
(byte) 0x65, (byte) 0x22, (byte) 0x3A, (byte) 0x22, (byte) 0xE5,
(byte) 0xBF, (byte) 0x97, (byte) 0xE5, (byte) 0x9B, (byte) 0xBD,
(byte) 0xED, (byte) 0xA0, (byte) 0xBD, (byte) 0xED, (byte) 0xB8,
(byte) 0x8F, (byte) 0xED, (byte) 0xA0, (byte) 0xBD, (byte) 0xED,
(byte) 0xB8, (byte) 0x92, (byte) 0xED, (byte) 0xA0, (byte) 0xBD,
(byte) 0xED, (byte) 0xB8, (byte) 0x93, (byte) 0xED, (byte) 0xA0,
(byte) 0xBD, (byte) 0xED, (byte) 0xB8, (byte) 0x94, (byte) 0xED,
(byte) 0xA0, (byte) 0xBD, (byte) 0xED, (byte) 0xB8, (byte) 0x9E,
(byte) 0xED, (byte) 0xA0, (byte) 0xBD, (byte) 0xED, (byte) 0xB8,
(byte) 0x9E, (byte) 0xED, (byte) 0xA0, (byte) 0xBD, (byte) 0xED,
(byte) 0xB8, (byte) 0x9E, (byte) 0xED, (byte) 0xA0, (byte) 0xBD,
(byte) 0xED, (byte) 0xB8, (byte) 0xA0, (byte) 0x22, (byte) 0x7D
};
直接发送这个字节数组,就会导致异常,如果将其创建为String,Java会将非法字符过滤,就不会报异常
过滤前
7b226e616d65223a22e5bf97e59bbdeda0bdedb88feda0bdedb892eda0bdedb893eda0bdedb894eda0bdedb89eeda0bdedb89eeda0bdedb89eeda0bdedb8a0227d
过滤后
7b226e616d65223a22e5bf97e59bbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd227d
过滤后的String
{"name":"志国����������������"}
Jackson和Gson不会出现这个问题
查看fastjson的源码后,发现FastJsonHttpMessageConverter会将请求内容的body字节数组直接传入解析方法,进一步测试,如果将此字节数组直接解析为Object,调用此Object的toString,即会报空指针异常。
Object o = JSONObject.parse(bytes);
System.out.println(o.toString());
此时返回的o为null,这种情况显然不是很合理
1条答案
按热度按时间ijxebb2r1#
进一步看代码后发现,JSON.parse这个函数中
UTF-8 decode的结果小于0的时候,结果是为空,直接解析的时候过程也是一样的。但是这个IOUtils.decodeUTF8的结果显然与Java对于非法字符的处理方案不同,这个函数会直接判定为错误,而Java新建String的时候会将它转换为固定的错误符号