multipart/mixed踩坑记录

  |   0 评论   |   0 浏览

背景

手头有一个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格式的头

结论

  1. 继续使用 SpringBoot Controller来处理multipart/mixed类型。