原因
先说下原因下,篇幅过长
时间节点(2020/01/20) Aliyun 的oss请求中Content-Type:multipart/form-data中的boundary不能用双引号包含
项目背景
某PC客户端项目中,需要将文件上传至Server进行文件保存,前期由Java后端进行中转传输。但是随着业务量的增加还有大文件的增多,导致后台无法承受住这些业务量。中期技术方案变更,由Server端返回oss相关 信息客户端通过Http直接将文件上传至阿里云的oss上
技术背景
使用QHttpMultiPart和QHttpPart构造Multipart消息体
问题发生
oss服务器返回MalformedPOSTRequest
<Code>MalformedPOSTRequest</Code>
<Message>The body of your POST request is not well-formed multipart/form-data</Message>
<RequestId>马赛克(_)</RequestId>
<HostId>aijihui-dev.oss-cn-hangzhou.aliyuncs.com</HostId>
问题定位
由于项目组使用的是成熟的Qt第三方底层库,错误的可能性很小
1.review code,查看使用是否有问题
2.抓包分析,目测header和body都没有问题
阿里云官网查阅相关文档以及FAQ
1.未找到相关信息
查阅RFC相关协议(rfc1867、rfc2046、rfc2616)
rfc2046 5.1.1
rfc2046-5.1.1.png
rfc2616 19.2
- Although RFC 2046 [40] permits the boundary string to be
quoted, some existing implementations handle a quoted boundary
string incorrectly.
查阅Qt底层代码
1.代码(code_1)先判断是否设置ContentTypeHeader
2.代码(code_2)将boundary用双引号包含,注释标明 recommended in RFC 2046 section 5.1.1
QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
{
// copy the request, we probably need to add some headers
QNetworkRequest newRequest(request);
// add Content-Type header if not there already
if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) { // code_1
// ....
}
// putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"'; // code_2
newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
}
// ...
return newRequest;
}
问题确认
Aliyun 的oss请求中Content-Type:multipart/form-data中的boundary不能用双引号包含
问题修改
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data;boundary=" + multiPart->boundary());
可能出现的bug:
如果{boundary}中生成含有':'的字符串可能会有问题