100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Qt——记录:http表单格式上传文件到七牛云和阿里云

Qt——记录:http表单格式上传文件到七牛云和阿里云

时间:2020-01-14 18:12:24

相关推荐

Qt——记录:http表单格式上传文件到七牛云和阿里云

环境:windows10

版本:Qt 5.15.2

工具:QtCreator

背景:通过http表单格式上传文件,兼容阿里云和七牛云。

一、记录问题:上传文件到阿里云

问题1:ErrorCode: MalformedPOSTRequest ErrorMessage: The body of your POST request is not well-formed multipart/form-data

分析:最初看到问题有点懵,后来看到这位大佬博客(http multipart上传阿里oss失败(MalformedPOSTRequest)_robin_xie1990的博客-CSDN博客)

Qt源码:

QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart){QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);QIODevice *device = multiPart->d_func()->device;QNetworkReply *reply = post(newRequest, device);return reply;}QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart){// copy the request, we probably need to add some headersQNetworkRequest newRequest(request);// add Content-Type header if not there alreadyif (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {QByteArray contentType;contentType.reserve(34 + multiPart->d_func()->boundary.count());contentType += "multipart/";switch (multiPart->d_func()->contentType) {case QHttpMultiPart::RelatedType:contentType += "related";break;case QHttpMultiPart::FormDataType:contentType += "form-data";break;case QHttpMultiPart::AlternativeType:contentType += "alternative";break;default:contentType += "mixed";break;}// putting the boundary into quotes, recommended in RFC 2046 section 5.1.1contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"'; //增加了双引号("")newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));}// add MIME-Version header if not there already (we must include the header// if the message conforms to RFC 2045, see section 4 of that RFC)QByteArray mimeHeader("MIME-Version");if (!request.hasRawHeader(mimeHeader))newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));QIODevice *device = multiPart->d_func()->device;if (!device->isReadable()) {if (!device->isOpen()) {if (!device->open(QIODevice::ReadOnly))qWarning("could not open device for reading");} else {qWarning("device is not readable");}}return newRequest;}

源码中提到:RFC 2046 section 5.1.1:RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types ()

红窗中意思:

Content-type字段上的参数语法通常需要将boundary的值括在Content-type行上的引号中。这并不总是必要的,但绝对没有坏处。实现者应该仔细学习语法,以避免产生无效的Content-type字段。因此,一个典型的“多部分”Content-Type报头字段可能是这样的。

我们看看阿里给的http表单示例:

POST / HTTP/1.1 Host: BucketName.oss-cn-User-Agent: browser_dataContent-Length:ContentLengthContent-Type: multipart/form-data; boundary=9431149156168--9431149156168Content-Disposition: form-data; name="key"key--9431149156168Content-Disposition: form-data; name="success_action_redirect"success_redirect--9431149156168Content-Disposition: form-data; name="Content-Disposition"attachment;filename=oss_download.jpg--9431149156168Content-Disposition: form-data; name="x-oss-meta-uuid"myuuid--9431149156168Content-Disposition: form-data; name="x-oss-meta-tag"mytag--9431149156168Content-Disposition: form-data; name="OSSAccessKeyId"access-key-id--9431149156168Content-Disposition: form-data; name="policy"encoded_policy--9431149156168Content-Disposition: form-data; name="Signature"signature--9431149156168Content-Disposition: form-data; name="file"; filename="MyFilename.jpg"Content-Type: image/jpegfile_content--9431149156168Content-Disposition: form-data; name="submit"Upload to OSS--9431149156168--

示例中的Content-Type: multipart/form-data; boundary=9431149156168 确实boundary值没加“”

获取Qt中的boundary,然后调用QHttpMultiPart类的setBoundary函数:

QNetworkRequest request(m_url);request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data;boundary=" + multiPart->boundary());

按照上述操作之后,果然可以正常上传文件到阿里云。

问题2:缺少空格也会导致问题1

问题3:我以为经过前两部设置就可以稳定上传到阿里云了,但是仍然会有偶发的报错,提示内容为The body of your POST request is not well-formed multipart/form-data{\"error\":\"invalidmultipartformat:mime:invalidmediaparameter\"}。不过报错情况只在特定情况出现:快速重复上传相同文件。问题原因仍然和boundary有关,后续和七牛云讲解。

一、记录问题:上传文件到七牛云

问题1:为了适配阿里云,去掉了Content-Type:multipart/form-data;boundary=boundary_.oOo._X/yX1rK+2zZTxLWhH9iaw425o/ 的双引号,但是上传到七牛云会报错The body of your POST request is not well-formed multipart/form-data{\"error\":\"invalidmultipartformat:mime:invalidmediaparameter\"}。这个错误和阿里云问题3一致。

分析问题:

最初boundary保留双引号时七牛云上传一直正常,去掉双引号之后,文件上传就不稳定。报错内容和阿里云再特定场景一致(问题3)。问题范围锁定在boundary。

分析1:看到报错信息提示为非法多媒体参数,怀疑是上传的文件或者格式是不是有问题。通过抓包分析查看上传的文件格式没问题,用相同文件也能上传成功,只不过不稳定。说明文件本身没问题。

分析2:否定分析1后,怀疑上传的表单数据是不是在解析时候出了问题。因此解决思路定位在boundary的作用上。boundary是分隔符,将上传的信息分隔成很多片段。boundary和上传的参数和数据混在一起,如果我们提取boundary不准确那我们上传的数据和参数可能都会错乱。这就意味着boundary在上传的信息中是个唯一的字符串,否则就会影响数据上传。

查看Qt帮我提供的boundary值:boundary_.oOo._X/yX1rK+2zZTxLWhH9iaw425o/ 看着还是挺复杂的,符号特别多。

怀疑是boundary值有问题后,利用Qt中的uuid生成唯一字符串,设置到表单中:

QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);QString uuid = QUuid::createUuid().toString();uuid.remove("{");uuid.remove("}");uuid = "test" + uuid;QString text = "multipart/form-data;boundary=" + QByteArray::fromStdString(uuid.toStdString());multiPart->setBoundary(QByteArray::fromStdString(uuid.toStdString()));

再次测试,七牛云可以稳定上传!!!后来七牛云给的反馈说boundary中的+和/会被替换掉。至于替换原因不知道。后续在文件上传到阿里云也没在出现过类似问题。

阿里云参考资料:

1.https表单:PostObject - API 参考| 阿里云 ()

2.Post Object错误及排查:阿里云帮助中心 ()

七牛云参考资料:

1. 问题排查:上传报文组装 - 七牛开发者中心 ()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。