环境:windows10

版本:Qt 5.15.2

工具:Qt Creator

背景:通过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 (ietf.org)

红窗中意思:

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

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

POST / HTTP/1.1
Host: BucketName.oss-cn-hangzhou.aliyuncs.com
User-Agent: browser_data
Content-Length:ContentLength
Content-Type: multipart/form-data; boundary=9431149156168
--9431149156168
Content-Disposition: form-data; name="key"
key
--9431149156168
Content-Disposition: form-data; name="success_action_redirect"
success_redirect
--9431149156168
Content-Disposition: form-data; name="Content-Disposition"
attachment;filename=oss_download.jpg
--9431149156168
Content-Disposition: form-data; name="x-oss-meta-uuid"
myuuid
--9431149156168
Content-Disposition: form-data; name="x-oss-meta-tag"
mytag
--9431149156168
Content-Disposition: form-data; name="OSSAccessKeyId"
access-key-id
--9431149156168
Content-Disposition: form-data; name="policy"
encoded_policy
--9431149156168
Content-Disposition: form-data; name="Signature"
signature
--9431149156168
Content-Disposition: form-data; name="file"; filename="MyFilename.jpg"
Content-Type: image/jpeg
file_content
--9431149156168
Content-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\":\"invalid multipart format: mime: invalid media parameter\"}。不过报错情况只在特定情况出现:快速重复上传相同文件。问题原因仍然和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\":\"invalid multipart format: mime: invalid media parameter\"}。这个错误和阿里云问题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 参考| 阿里云 (alibabacloud.com)

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

七牛云参考资料:

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

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

  1. PHP上传文件到七牛云和阿里云

    七牛云上传 注册七牛云账号并认证 进入控制台找到对象存储添加一个新的仓库 添加完成之后看文档 安装 使用 Composer 安装 Composer是 PHP 依赖管理工具.你可以在自己的项目中声明所依 ...

  2. 关于前端上传文件到七牛云的一些笔记

    关于前端上传文件到七牛云的一些心得 前言 申请账户 具体步骤 算了 小技巧 七牛云没有监控上传进度和上传错误的 API ?(JS SDK) React 更新 state 中的数组不能触发动画效果? 前 ...

  3. Go语言实战-通过gin上传文件到七牛云OSS

    上传到文件到七牛云的两种上传方式: 1. 客户端上传到服务器,服务器再上传到七牛云 2.客户端直接通过ajax上传到七牛云 前者:需要上传到服务器,这个过程需要消耗不少带宽,也给服务器带来不小压力,但 ...

  4. 七牛云配置 koa 上传文件到七牛云

    一.七牛云配置 七牛官网 1.创建七牛存储空间 2.空间添加备案的域名 (若是测试空间可不需要配置) 3.解析CNAME 添加域名后会有CNAME(别名记录),需要将它解析到你的备案域名下 链接-CN ...

  5. Spring boot上传文件(图片)到阿里云OSS(直接上传到应用服务器)

    Spring boot上传文件(图片)到阿里云OSS(直接上传到应用服务器) 主要思路 上传图片的思路有两种: 第一种是上传到应用服务器,再由应用服务器上传到OSS.这种适合上传的文件较小,较为简单, ...

  6. 前端通过ajax上传文件到七牛云

    1. 从服务端获取七牛云上传的token,生成token参考官方文档https://developer.qiniu.com/kodo/1208/upload-token 2. 在七牛云文档查找上传的存 ...

  7. Android Okhttp3的使用(很全面,包含Post提交字符串、键值对、表单、上传文件、无参请求和Get有参无参请求,还有自动添加token)

    Okhttp简介 okhttp是现代化应用程序的网络通信的方式.它用来帮助程序交换数据和媒体信息,使用okhttp可以让你的程序加载物料(翻译为服务器数据更合适在)更加高效.更节省网络带宽. okht ...

  8. ajax 提交form表单,上传文件

    参考 :https://blog.csdn.net/gu_wen_jie/article/details/72177714 注意:使用layui 按钮提交表单时,按钮会默认提交表单.解决如下: $(' ...

  9. 前端实现axios以表单方式上传文件,优化上传速度

    一.背景 最近在开发过程中,遇到的需要是需要上传高清图片,必须原图上传.由于在移动端应用,上传网络问题有很大的坑.当初的方案是直接采用将文件转化为base64,再进行上传,由于文件转化为base64后 ...

最新文章

  1. b站前端大佬_最强UP主:罗翔老师,你凭什么打败B站千万粉大佬老番茄?
  2. JSR349(Bean Validation 1.1)
  3. Disconf介绍,源码下载,环境准备,安装,disconf-web使用和配置介绍,项目中进行配置,项目案例运行
  4. java jsp学习指南_JSP教程–最终指南
  5. nginx 不带www到www域名的重定向
  6. php while mysql_我怎么能避免在PHP的While循环中使用MySQL查询
  7. mysql实现行转列功能
  8. 模式识别算法:SVM支持向量机
  9. U盘之家工具包 V1.4
  10. r语言跟python哪个适合数据分析_R语言 vs Python对比:数据分析哪家强?
  11. 什么是DOS操作系统
  12. 有哪些简洁好看且能高效整理信息的便签软件
  13. Laya之微信小游戏入门
  14. gpg加密命令 linux_使用 GPG 加密和解密文件
  15. NLM_B-A non-local algorithm for image denoising分享
  16. 2022年复合挤出机市场前景分析及研究报告
  17. 不同手机型号图文预览_关于iPhone的不同型号手机和不同版本系统
  18. 网络拓扑abor.js库---力导向
  19. 【Android取证篇】Android设备USB调试打开方式(开发者模式)
  20. pandownload内部测试版

热门文章

  1. 2023 年五个最佳被动收入来源
  2. 矩阵的对数运算公式_HanLP-对数概率转概率
  3. UI设计薪资水涨船高,你是否适合学习呢?
  4. Scapy介绍官方文档翻译
  5. pclint 与coverity
  6. 计算机财务管理名词解释,管理会计的名词解释
  7. Anroid/Linux 下查看麦克风或音频采集设备
  8. 利用ENVI对遥感图像校正
  9. Python——pyqt-auto-tool自动化小工具(源码)
  10. 高中计算机语言有哪些,高中有哪些