multipart/mixed踩坑记录
背景
手头有一个SpringBoot的http服务,希望改造成netty实现的。
但是改造完成后,发现线上报错,netty无法解析POST参数。
详细经过
netty实现http服务
其中http服务代码片断,和解码的代码片断如下。
ChannelPipeline p = ch.pipeline();
//以下三个是Http的支持
//http解码器
p.addLast("http-codec", new HttpServerCodec());
//支持写大数据流
p.addLast("chunked-write", new ChunkedWriteHandler());
//http聚合器
p.addLast("http-aggregator", new HttpObjectAggregator(1024 * 512));
p.addLast("server-handler", new CustomHttpServerHandler(parentGroup, childGroup));
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(
new DefaultHttpDataFactory(false), req);
InterfaceHttpData data = decoder.getBodyHttpData(name);
if (data.getHttpDataType() == HttpDataType.Attribute) {
Attribute attribute = (Attribute) data;
String value = null;
try {
value = attribute.getValue();
} catch (IOException e) {
e.printStackTrace();
}
return value;
}
自测情况
使用 fluent-hc 请求netty服务,过程是符合预期的。
但是使用 okhttp3 请求netty服务,会报错。
抓包分析
fluent-hc的包如下:
T 127.0.0.1:58552 -> 127.0.0.1:8081 [AP] #5
POST /asr/sync HTTP/1.1.
appkey: ItKBnssbLm.
time: 1694796499868.
authCode: aXJGd0FBQUZsQk1ROEFBQUFBQUFBQUFEd0FBQURUaWdSbEFBQUFBUE9tQkdVQUFBQUFNMlF4TWpJelpHSTRaVGRrWlRVNFl3QUFBQUFCL3dEL01FVUNJUUNHSnNVaXNPRmtXR
nJFMTZmdHRJaTAxaDFoaXZacTV5QUNVRDBUK0UyOWJBSWdQbU9MWFBvVTljV0xmRnkvRCszOXNMTXNxS1pIRlZ5Q2lMQ3BORFVZdkFNQUFBQXVSdz09.
Content-Length: 38829.
Content-Type: multipart/form-data; boundary=q5WJKqU45BfshrS543WrN3LR01CyQsR5I2NlhcA.
Host: 127.0.0.1:8081.
Connection: Keep-Alive.
User-Agent: Apache-HttpClient/4.5.13 (Java/1.8.0_311).
Accept-Encoding: gzip,deflate.
.
--q5WJKqU45BfshrS543WrN3LR01CyQsR5I2NlhcA.
Content-Disposition: form-data; name="sampleRate".
Content-Type: text/plain; charset=ISO-8859-1.
Content-Transfer-Encoding: 8bit.
.
16000
##
T 127.0.0.1:58552 -> 127.0.0.1:8081 [AP] #7
.
--q5WJKqU45BfshrS543WrN3LR01CyQsR5I2NlhcA.
Content-Disposition: form-data; name="requestId".
Content-Type: text/plain; charset=ISO-8859-1.
Content-Transfer-Encoding: 8bit.
.
11111
okhttp的包如下:
T 127.0.0.1:58441 -> 127.0.0.1:8081 [AP] #5
POST /asr/sync HTTP/1.1.
appKey: BFInqALgVF.
authCode: aXJGd0FBQUZsQk1ROEFBQUFBQUFBQUFEd0FBQUNmaWdSbEFBQUFBTCttQkdVQUFBQUFOemhqTkRaa016UmlOMk0yWWpFeFlRQUFBQUFCL3dEL01FVUNJUURDNzhhQWMvME5GV
XZhb0tXUE5neER5bldFT0k5OFVpcGJiVnUvSC85aC93SWdKYmY3aisvSTRob1FJKzQzQVl3b3Rlb3lxUWUzRlJIYjZPMnZ0a0FoeE44QUFBQXVSdz09.
time: 1694796447597.
appkey: BFInqALgVF.
Content-Type: multipart/mixed; boundary=d8fd9dd6-376d-4324-8b6f-634538112fde.
Content-Length: 38580.
Host: 127.0.0.1:8081.
Connection: Keep-Alive.
Accept-Encoding: gzip.
User-Agent: okhttp/3.14.0.
.
##
T 127.0.0.1:58441 -> 127.0.0.1:8081 [AP] #7
--d8fd9dd6-376d-4324-8b6f-634538112fde.
Content-Disposition: form-data; name="sampleRate".
Content-Length: 5.
.
16000.
--d8fd9dd6-376d-4324-8b6f-634538112fde.
Content-Disposition: form-data; name="requestId".
Content-Length: 5.
.
11111.
--d8fd9dd6-376d-4324-8b6f-634538112fde.
可见,fluent-hc的头为Content-Type: multipart/form-data
,但是okhttp 3.14.0的头为Content-Type: multipart/mixed
。
查看netty如何解析multipart/mixed
从 https://github.com/netty/netty/issues/7647 找到了,netty认为根据RFC 1867规范,只允许 multipart/form-data
的头。
所以netty的HttpPostRequestDecoder
代码中,也只支持 multipart/form-data
格式的头
结论
- 继续使用 SpringBoot Controller来处理
multipart/mixed
类型。