如何使用multipart/form-data格式上传文件

2023-11-04

------------------------------------------------------------------
大家好,我是许飞,微软拼音的开发实习生。在网络编程中,经常用到从服务器上“下载”一些数据,有时却要向服务器“上传”数据。曾在一个原型中使用了“multipart/form-data”格式向Web服务器上传文件,这里和大家分享。
------------------------------------------------------------------ 
有时,在网络编程过程中需要向服务器上传文件。Multipart/form-data是上传文件的一种方式。

Multipart/form-data其实就是浏览器用表单上传文件的方式。最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用multipart/form-data格式上传到服务器。

表单形式上传附件

具体的步骤是怎样的呢?

首先,客户端和服务器建立连接(TCP协议)。

第二,客户端可以向服务器端发送数据。因为上传文件实质上也是向服务器端发送请求。

第三,客户端按照符合“multipart/form-data”的格式向服务器端发送数据。

Multipart/form-data的格式是怎样的呢?

既然Multipart/form-data格式就是浏览器用表单提交数据的格式,我们就来看看文件经过浏览器编码后是什么样子。

HTML表单

浏览器打开的表单

 

点击“Browse…”分别选择“unknow.gif”和“unknow1.gif”文件,点击“submit”按纽后,文件将被上传到服务器。

下面是服务器收到的数据:

服务器收到的数据

这是一个POST请求。所以数据是放在请求体内,而不是请求头内。

这行指出这个请求是“multipart/form-data”格式的,且“boundary”是 “---------------------------7db15a14291cce”这个字符串。

不难想象,“boundary”是用来隔开表单中不同部分数据的。例子中的表单就有 2 部分数据,用“boundary”隔开。“boundary”一般由系统随机产生,但也可以简单的用“-------------”来代替。

实际上,每部分数据的开头都是由"--" + boundary开始,而不是由 boundary 开始。仔细看才能发现下面的开头这段字符串实际上要比 boundary 多了个 “--”

clip_image011

紧接着 boundary 的是该部分数据的描述。

接下来才是数据。

“GIF”gif格式图片的文件头,可见,unknow1.gif确实是gif格式图片。

在请求的最后,则是 "--" + boundary + "--" 表明表单的结束

 

需要注意的是,在html协议中,用 “/r/n” 换行,而不是 “/n”

下面的代码片断演示如何构造multipart/form-data格式数据,并上传图片到服务器。

[c-sharp]  view plain copy
  1. //---------------------------------------  
  2.   
  3. // this is the demo code of using multipart/form-data to upload text and photos.  
  4.   
  5. // -use WinInet APIs.  
  6.   
  7. //  
  8.   
  9. //  
  10.   
  11. // connection handlers.  
  12.   
  13. //  
  14.   
  15. HRESULT hr;  
  16.   
  17. HINTERNET m_hOpen;   
  18.   
  19. HINTERNET m_hConnect;  
  20.   
  21. HINTERNET m_hRequest;  
  22.   
  23. //  
  24.   
  25. // make connection.  
  26.   
  27. //  
  28.   
  29. ...  
  30.   
  31. //  
  32.   
  33. // form the content.  
  34.   
  35. //  
  36.   
  37. std::wstring strBoundary = std::wstring(L"------------------");  
  38.   
  39. std::wstring wstrHeader(L"Content-Type: multipart/form-data, boundary=");  
  40.   
  41. wstrHeader += strBoundary;  
  42.   
  43. HttpAddRequestHeaders(m_hRequest, wstrHeader.c_str(), DWORD(wstrHeader.size()), HTTP_ADDREQ_FLAG_ADD);  
  44.   
  45. //  
  46.   
  47. // "std::wstring strPhotoPath" is the name of photo to upload.  
  48.   
  49. //  
  50.   
  51. //  
  52.   
  53. // uploaded photo form-part begin.  
  54.   
  55. //  
  56.   
  57. std::wstring strMultipartFirst(L"--");  
  58.   
  59. strMultipartFirst += strBoundary;  
  60.   
  61. strMultipartFirst += L"/r/nContent-Disposition: form-data; name=/"pic/"; filename=";  
  62.   
  63. strMultipartFirst += L"/"" + strPhotoPath + L"/"";  
  64.   
  65. strMultipartFirst += L"/r/nContent-Type: image/jpeg/r/n/r/n";  
  66.   
  67. //  
  68.   
  69. // "std::wstring strTextContent" is the text to uploaded.   
  70.   
  71. //  
  72.   
  73. //  
  74.   
  75. // uploaded text form-part begin.  
  76.   
  77. //  
  78.   
  79. std::wstring strMultipartInter(L"/r/n--");  
  80.   
  81. strMultipartInter += strBoundary;  
  82.   
  83. strMultipartInter += L"/r/nContent-Disposition: form-data; name=/"status/"/r/n/r/n";  
  84.   
  85. std::wstring wstrPostDataUrlEncode(CEncodeTool::Encode_Url(strTextContent));  
  86.   
  87. // add text content to send.  
  88.   
  89. strMultipartInter += wstrPostDataUrlEncode;  
  90.   
  91. std::wstring strMultipartEnd(L"/r/n--");  
  92.   
  93. strMultipartEnd += strBoundary;  
  94.   
  95. strMultipartEnd += L"--/r/n";  
  96.   
  97. //  
  98.   
  99. // open photo file.  
  100.   
  101. //  
  102.   
  103. // ws2s(std::wstring)  
  104.   
  105. // -transform "strPhotopath" from unicode to ansi.  
  106.   
  107. std::ifstream *pstdofsPicInput = new std::ifstream;  
  108.   
  109. pstdofsPicInput->open((ws2s(strPhotoPath)).c_str(), std::ios::binary|std::ios::in);  
  110.   
  111. pstdofsPicInput->seekg(0, std::ios::end);  
  112.   
  113. int nFileSize = pstdofsPicInput->tellg();  
  114.   
  115. if(nPicFileLen == 0)  
  116.   
  117. {  
  118.   
  119. return E_ACCESSDENIED;  
  120.   
  121. }  
  122.   
  123. char *pchPicFileBuf = NULL;  
  124.   
  125. try  
  126.   
  127. {  
  128.   
  129. pchPicFileBuf = new char[nPicFileLen];  
  130.   
  131. }  
  132.   
  133. catch(std::bad_alloc)  
  134.   
  135. {  
  136.   
  137. hr = E_FAIL;  
  138.   
  139. }  
  140.   
  141. if(FAILED(hr))  
  142.   
  143. {  
  144.   
  145. return hr;  
  146.   
  147. }  
  148.   
  149. pstdofsPicInput->seekg(0, std::ios::beg);  
  150.   
  151. pstdofsPicInput->read(pchPicFileBuf, nPicFileLen);  
  152.   
  153. if(pstdofsPicInput->bad())  
  154.   
  155. {  
  156.   
  157. pstdofsPicInput->close();  
  158.   
  159. hr = E_FAIL;  
  160.   
  161. }  
  162.   
  163. delete pstdofsPicInput;  
  164.   
  165. if(FAILED(hr))  
  166.   
  167. {  
  168.   
  169. return hr;  
  170.   
  171. }  
  172.   
  173. // Calculate the length of data to send.  
  174.   
  175. std::string straMultipartFirst = CEncodeTool::ws2s(strMultipartFirst);  
  176.   
  177. std::string straMultipartInter = CEncodeTool::ws2s(strMultipartInter);  
  178.   
  179. std::string straMultipartEnd = CEncodeTool::ws2s(strMultipartEnd);  
  180.   
  181. int cSendBufLen = straMultipartFirst.size() + nPicFileLen + straMultipartInter.size() + straMultipartEnd.size();  
  182.   
  183. // Allocate the buffer to temporary store the data to send.  
  184.   
  185. PCHAR pchSendBuf = new CHAR[cSendBufLen];  
  186.   
  187. memcpy(pchSendBuf, straMultipartFirst.c_str(), straMultipartFirst.size());  
  188.   
  189. memcpy(pchSendBuf + straMultipartFirst.size(), (const char *)pchPicFileBuf, nPicFileLen);  
  190.   
  191. memcpy(pchSendBuf + straMultipartFirst.size() + nPicFileLen, straMultipartInter.c_str(), straMultipartInter.size());  
  192.   
  193. memcpy(pchSendBuf + straMultipartFirst.size() + nPicFileLen + straMultipartInter.size(), straMultipartEnd.c_str(), straMultipartEnd.size());  
  194.   
  195. //  
  196.   
  197. // send the request data.  
  198.   
  199. //  
  200.   
  201. HttpSendRequest(m_hRequest, NULL, 0, (LPVOID)pchSendBuf, cSendBufLen)  
  202.   
  203. ...  


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用multipart/form-data格式上传文件 的相关文章

  • 将 HttpApi 与 I/O 完成端口结合使用

    我刚刚偶然发现了微软的HTTP 服务器 API http msdn microsoft com en us library aa364510 28v vs 85 29 aspx 简介中写道 HTTP 服务器 API 使应用程序能够通过 HT
  • 我应该使用多个 HttpClient 来进行批量异步 GET 请求吗?

    我有一个场景 我需要在尽可能短的时间内发出大量 GET 请求 想想大约 1000 个 我知道通常最好保留一个客户端并尽可能重用它 Create Single HTTP Client HttpClient client new HttpCli
  • python 2.7 中的 HTTP 2 请求

    在 python 中向 HTTP 1 和 HTTP 2 发出请求有什么区别吗 我可以像这样在 python 中进行 HTTP 1 x 调用 url http someURL values param1 key param2 key2 dat
  • 诸如用于测试 HTTP 请求的虚拟 REST 服务器之类的东西? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我一直在四处寻找 但找不到任何这样的网站 我想知道是否有一些虚拟服务器可以响应测试 GET 请求并返回
  • 服务器响应中的“连接:保持活动状态”

    我正在尝试建立从 Silverlight 应用程序到 Apache 服务器托管的 PHP 页面的 HTTP 持久连接 即无需为每个 HTTP 请求创建新的 TCP 连接 为此 我需要网络服务器发送其 HTTP 响应 并将 Connectio
  • WCF WebHttp 混合身份验证(基本和匿名)

    所有这些都与 WebHttp 绑定有关 托管在自定义服务主机中 IIS 目前不是一个选项 我已经实现了自定义 UserNamePasswordValidator 和自定义 IAuthorizationPolicy 当我将端点的绑定配置为使用
  • 用 C++ 解析 HTTP 标头

    我正在使用curl 与服务器通信 当我发出数据请求时 我收到 HTTP 标头 后跟由边界分隔的 jpeg 数据 如下所示 我需要解析出 边界字符串 内容长度 我已将传入数据复制到 char 数组 如下所示 static size t OnR
  • 使用 Unity 在 C# 中发送 http 请求

    如何使用 Unity 在 C 中发送 HTTP GET 和 POST 请求 我想要的是 在post请求中发送json数据 我使用Unity序列化器 所以不需要 新的 我只想在发布数据中传递一个字符串并且能够 将 ContentType 设置
  • Angular 2 - Http - 正确忽略空结果

    我有很多处理请求并简单返回 200 的 REST 端点 我注意到将结果映射为错误json 如果我尝试不进行任何类型的映射 我会看到浏览器警告它无法解析 XML 由于不返回任何内容是很常见的 我很好奇我应该如何处理响应 这是一个基本的代码示例
  • 为什么我的 Github 托管网站响应 HTTP 302 而不是 200?

    我拥有该域名penkov id au http penkov id au 我主持一个blog http michael penkov id au blog 2014 01 02 reinventing the wheel html usin
  • 使用 file_get_content 发布数据

    我已经做了一些关于如何使用的研究file get content与帖子 我也读过this one https stackoverflow com questions 2445276 how to post data in php using
  • android httprequest java.net.UnknownHostException

    我想用android发出http请求 是使用这个 void testHTTP HttpClient httpClient new DefaultHttpClient HttpUriRequest request new HttpPost h
  • 我可以从 HTTP 请求中找到无线接入点的 BSSID(MAC 地址)吗?

    假设有人在咖啡店里无线连接到互联网 并向 johnsveryownserver com 发送 HTTP 请求 服务器端 有什么方法可以确定我的MAC地址吗 无线接入点他们连接到什么 请注意 我对他们机器的 MAC 地址不感兴趣 如果我无法使
  • Android httpclient文件上传数据损坏和超时问题

    我在 Android 中上传图像时遇到问题 我正在使用 apache httpmime 4 1 lib 代码是这样的 MultipartEntity reqEntity new MultipartEntity HttpMultipartMo
  • 如何在java中以编程方式访问网页

    有一个网页 我想从中检索某个字符串 为此 我需要登录 单击一些按钮 填充文本框 单击另一个按钮 然后就会出现字符串 我怎样才能编写一个java程序来自动执行此操作 是否有任何有用的库用于此目的 Thanks Try HtmlUnit htt
  • 如何将所有GET请求查询参数放入Go中的结构体中?

    你好 我想将 get 查询参数转换为 Go 中的结构 例如我有这样的结构 type Filter struct Offset int64 json offset Limit int64 json limit SortBy string js
  • Go客户端程序生成大量TIME_WAIT状态的socket

    我有一个 Go 程序 它从多个 goroutine 生成大量 HTTP 请求 运行一段时间后 程序报错 connect cannot allocaterequestedaddress 当检查时netstat 我得到大量 28229 个连接T
  • 使用 Java 通过 HTTP 下载未知长度的文件

    我想用java下载一个HTTP查询 但是我下载的文件在下载时有一个未确定的长度 我认为这将是相当标准的 所以我搜索并找到了它的代码片段 http snipplr com view 33805 http snipplr com view 33
  • HTTP请求的内容长度>正文大小

    我正在管理一个网站 该网站过去几个月在使用 MVC 3 0 ASP net 构建的 IIS 7 5 上运行良好 当我们的 AJAX POST 请求 通过 jQuery 触发 因发布的 JSON 被截断而失败时 我们时不时地会遇到一个问题 到
  • 为 REST API 编写单元测试的最佳方法是什么?

    在为 API 包装器编写单元测试时 我应该对 REST API 端点进行真正的调用 还是应该使用 mocl 响应来模拟成功和错误的调用 单元测试意味着只测试你的unit API 包装器 仅此而已 因此 不幸的是 您应该模拟整个 API 另一

随机推荐

  • windows10: vscode conda activate CommandNotFoundError

    Windows10 在vscode中自动激活环境报错 CommandNotFoundError 转载自 https www cnblogs com weixia blog p 11408125 html 最近重装了系统 装完anaconda
  • 小程序微信支付

    微信小程序实现支付功能 1 准备工作 在开始实现微信小程序支付功能之前 我们需要先完成以下准备工作 注册微信支付商户号 并完成商户资质审核 微信支付开发文档 在小程序中引入微信支付JSAPI 获取用户的openid 用于发起支付请求 2 支
  • 【Python】模块

    模块 就类似于我们生活中的工具包 Python中的源程序可以作为模块 我们需要使用时 直接将模块导入到我们需要使用的源程序中即可 目录 模块 导入模块 模块导入原理 局部导入 包 包的定义 模块的使用 模块 导入模块 我们导入模块使用的是i
  • Mybatis-Plus查询或更新报错

    报错 Error evaluating expression ew null and ew sqlFirst null Cause org apache ibatis ognl OgnlException sqlFirst 原因 Query
  • SD-WAN与MPLS VPN,MSTP,IPSEC VPN,SSL VPN有什么区别?

    对于目前市场上主流的SD WAN MPLS VPN SSL VPN IPSec VPN和MSTP等企业组网技术 想必大家一定不陌生 其实 MPLS VPN IPSec VPN SSL VPN都属于采用IP VPN技术的产品 IP VPN 虚
  • 重新启动elasticsearch 报错:org.elasticsearch.bootstrap.StartupException: java.lang.IllegalStateException:

    cmd命令重新启动elasticsearch 报错 org elasticsearch bootstrap StartupException java lang IllegalStateException failed to obtain
  • java连接oracle数据库的各种方法及java在数据库中的含义

    java连接oracle数据库的各种方法及java在数据库中的含义 java与oracle的接口 在数据库中运行JAVA可以说是ORACLE8i的最令人激动的新特性 在你创建的使用ORACLE8i 数据库的应用程序中 你可以使用与JAVA有
  • 转载:图像噪声的成因分类与常见图像去噪算法简介

    本文转载自博客园博主淇淇宝贝 图像的空域噪声以及二维降噪算法介绍 1 图像噪声的成因 图像在生成和传输过程中常常因受到各种噪声的干扰和影响而是图像降质 这对后续图像的处理和图像视觉效应将产生不利影响 噪声种类很多 比如 电噪声 机械噪声 信
  • YOLOv5:Profile、Timeout、WorkingDirectory上下文管理器 以及torch.cuda.synchronize()

    相关介绍 Python是一种跨平台的计算机程序设计语言 是一个高层次的结合了解释性 编译性 互动性和面向对象的脚本语言 最初被设计用于编写自动化脚本 shell 随着版本的不断更新和语言新功能的添加 越多被用于独立的 大型项目的开发 Pyt
  • 因果推断(三)——结构因果模型、干预、辛普森悖论

    主要内容 结构因果模型 干预 辛普森悖论 调整公式 结构因果模型 Structural Causal Model SCM 定义 结构因果模型被定义为一个有序三元组
  • jTable设置单个单元格颜色

    尝试Swing已经一星期 感觉Swing里的坑还是很多的 对于我这种刚入门的新手来说 接口确实有些不顺手 闲话休提 需求是这样的 绘制一个数据表格 假如其中某个单元格的数据超出阈值 该单元格标红 在Swing的库里简略地翻了一阵子的结果是
  • 《Thinking in java》笔记

    thinking in java 引发的思考 关于java面向对象的思考 抽象 并发 thinking in java中1 1抽象过程的描述 问题空间 gt 解空间的映射 所有问题最终都是列表 所有问题最终都是算法 面向对象 对象是现实世界
  • 向日葵win10控制Ubuntu失败怎么办

    服务器Ubuntu18 04 我的个人电脑win10 服务器端控制win10没问题 但是win10控制不了Ubuntu 这是因为向日葵在Ubuntu上没有开放xhost造成的 在Ubuntu的终端输入以下命令 sudo gedit etc
  • 曙光服务器重装系统centos7.9

    我的诉求是重装系统 清空所有 因此在划分磁盘的地方把以前的全部删了 朋友们谨慎参考 大致的思路就是 1 刻录一个带有新系统的U盘 系统可能和服务器硬件不兼容 因此建议搞俩系统 2 在服务器旁边 连接显示屏操作
  • python 实现自动上传文件到百度网盘(附程序源码及实现过程)

    把环境搭建完成之后就可以上传文件到自己的百度网盘中 环境搭建移步 环境准备 python3 6 firefox 最好是最新版 不然不会报错 Windows 7 框架搭建 selenium3 6 安装方法 pip install seleni
  • Windows下的socket编程

    前言 经过一周的时间 我又回来啦 这周我主要学习的是Windows下的socket网络编程 本篇博客的内容包括socket的简介 TCP IP协议的讲解 TCP socket编程实例 UDP socket编程实例以及相关类的封装 涉及到的知
  • 基类和派生类之间构造函数和析构函数的调用顺序

    笔者面试时 经常被问到基类和派生类之间构造函数和析构函数的调用顺序的问题 今天写个简单程序记录一下 include
  • python怎么换行输代码_python输代码怎么换行?

    python是一种计算机脚本语言 它语言简洁明了 实现也非常简单 但是有时对编写风格不是很熟悉的话 做起来也是不太方便 下面小编将带大家一起学习一下 在输入Python语句时如何换行 有朋友可能会想到 直接enter一下不就行了吗 但实际上
  • MMDeteceion V3版之系列一(环境安装、模型测试、训练以及模型后处理工具)

    1 MMDeteceion初识 MMDetection是一款优秀的基于PyTorch的深度学习目标检测工具箱 由香港中文大学 CUHK 多媒体实验室 mmlab 开发 基本上支持所有当前SOTA二阶段的目标检测算法 比如faster rcn
  • 如何使用multipart/form-data格式上传文件

    如何使用multipart form data格式上传文件 大家好 我是许飞 微软拼音的开发实习生 在网络编程中 经常用到从服务器上 下载 一些数据 有时却要向服务器 上传 数据 曾在一个原型中使用了 multipart form data