Qt——记录:http表单格式上传文件到七牛云和阿里云
环境: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表单格式上传文件到七牛云和阿里云相关推荐
- PHP上传文件到七牛云和阿里云
七牛云上传 注册七牛云账号并认证 进入控制台找到对象存储添加一个新的仓库 添加完成之后看文档 安装 使用 Composer 安装 Composer是 PHP 依赖管理工具.你可以在自己的项目中声明所依 ...
- 关于前端上传文件到七牛云的一些笔记
关于前端上传文件到七牛云的一些心得 前言 申请账户 具体步骤 算了 小技巧 七牛云没有监控上传进度和上传错误的 API ?(JS SDK) React 更新 state 中的数组不能触发动画效果? 前 ...
- Go语言实战-通过gin上传文件到七牛云OSS
上传到文件到七牛云的两种上传方式: 1. 客户端上传到服务器,服务器再上传到七牛云 2.客户端直接通过ajax上传到七牛云 前者:需要上传到服务器,这个过程需要消耗不少带宽,也给服务器带来不小压力,但 ...
- 七牛云配置 koa 上传文件到七牛云
一.七牛云配置 七牛官网 1.创建七牛存储空间 2.空间添加备案的域名 (若是测试空间可不需要配置) 3.解析CNAME 添加域名后会有CNAME(别名记录),需要将它解析到你的备案域名下 链接-CN ...
- Spring boot上传文件(图片)到阿里云OSS(直接上传到应用服务器)
Spring boot上传文件(图片)到阿里云OSS(直接上传到应用服务器) 主要思路 上传图片的思路有两种: 第一种是上传到应用服务器,再由应用服务器上传到OSS.这种适合上传的文件较小,较为简单, ...
- 前端通过ajax上传文件到七牛云
1. 从服务端获取七牛云上传的token,生成token参考官方文档https://developer.qiniu.com/kodo/1208/upload-token 2. 在七牛云文档查找上传的存 ...
- Android Okhttp3的使用(很全面,包含Post提交字符串、键值对、表单、上传文件、无参请求和Get有参无参请求,还有自动添加token)
Okhttp简介 okhttp是现代化应用程序的网络通信的方式.它用来帮助程序交换数据和媒体信息,使用okhttp可以让你的程序加载物料(翻译为服务器数据更合适在)更加高效.更节省网络带宽. okht ...
- ajax 提交form表单,上传文件
参考 :https://blog.csdn.net/gu_wen_jie/article/details/72177714 注意:使用layui 按钮提交表单时,按钮会默认提交表单.解决如下: $(' ...
- 前端实现axios以表单方式上传文件,优化上传速度
一.背景 最近在开发过程中,遇到的需要是需要上传高清图片,必须原图上传.由于在移动端应用,上传网络问题有很大的坑.当初的方案是直接采用将文件转化为base64,再进行上传,由于文件转化为base64后 ...
最新文章
- b站前端大佬_最强UP主:罗翔老师,你凭什么打败B站千万粉大佬老番茄?
- JSR349(Bean Validation 1.1)
- Disconf介绍,源码下载,环境准备,安装,disconf-web使用和配置介绍,项目中进行配置,项目案例运行
- java jsp学习指南_JSP教程–最终指南
- nginx 不带www到www域名的重定向
- php while mysql_我怎么能避免在PHP的While循环中使用MySQL查询
- mysql实现行转列功能
- 模式识别算法:SVM支持向量机
- U盘之家工具包 V1.4
- r语言跟python哪个适合数据分析_R语言 vs Python对比:数据分析哪家强?
- 什么是DOS操作系统
- 有哪些简洁好看且能高效整理信息的便签软件
- Laya之微信小游戏入门
- gpg加密命令 linux_使用 GPG 加密和解密文件
- NLM_B-A non-local algorithm for image denoising分享
- 2022年复合挤出机市场前景分析及研究报告
- 不同手机型号图文预览_关于iPhone的不同型号手机和不同版本系统
- 网络拓扑abor.js库---力导向
- 【Android取证篇】Android设备USB调试打开方式(开发者模式)
- pandownload内部测试版