最近在做一个文件上传的开放接口,用到Content-Type: multipart/form-data这种请求类型,特地做了一些研究和记录。

在最初的 http协议中,并没有上传文件方面的功能。RFC1867为 http协议添加了这个能力。常见的浏览器,如 Microsoft IE, Mozila, Opera, Chrome,Safari等都已经支持。按照此规范将用户指定的文件发送到服务器。服务器端的程序如 java等,可以按照此规范解析出用户发送来的文件。

RFC1867定义的请求格式如下示例:

------ZcyOpenBoundaryEEpIo3GVWKVCPrX8Content-Disposition: form-data; name="_data_"Content-Type: text/plain; charset=UTF-8Content-Transfer-Encoding: 8bit{"fileName":"redis-use.png","bizCode":"1071"}------ZcyOpenBoundaryEEpIo3GVWKVCPrX8Content-Disposition: form-data; name="file"; filename="deaultFilename"Content-Type: application/octet-streamContent-Transfer-Encoding: binaryÿØÿàJFIFÿÛC      $.' ",#(7),01444'9=82<.>342ÿÛC       ÿÀ22"ÿÄÿÄ3!1Aa"Qq¡Á2BR#3¢±ÿÄÿÄ !13QAÿÚ?ÇÛ{çZ3ãçjãêµrÖåcñ÷·µO åÃKë¥Tv®ÊhíI§~2,ºFT4É÷åò©Ëë¹¢Y¼9 etúÍD=ÞØâ¡1Mº  :î~þõStY)vè°l¦t¶îðâHùË=E>ÿ¤R3µ³/îEæÞb¿¸Í  §\6£O­J#4Ý÷åFÀÕh_E5âw¢§ßg®÷1V¯/­Å·Ô³nDÞ=9ÏÒªi ,xïS^2Ûx¦ÊF²åÐåHûÒ¬±}K;h×ZóøÂîïÝÐàx®Z4]©¦àr_Ç-yç½q4Ó2FVÎÀáïåì\Ó¯á×%½6[=Pë9lëÔcJcæ;-²½Ø'ÒPÝÈË5ÉÎ=´©%¶·ÜFc«1%±Û'SL?´íã8¢¶y@zc^]»Tm8·Ss"É1æQwGË'þÔÁ¢ÊQçYµmÁÐýimclä4§H35ÕÛlÅp4=¥,·(íA~xçO~]êjWÒªçók­gëæ%¼lª&27ër[áL¤ñÌr7¦II?¹4©`Q^Í,$¤gw9î(¬ÃùÝÆSþTØÿ쯨]?WÞ«¾%b¯C]EVÊÎoþÂ:Ùê¦î,¨>¡Ìw¢Ô0K7£ô.¬:TÒ${B0ª  1E¢æUãÉéôïEQ  ÿÙ...省略部分内容...------ZcyOpenBoundaryEEpIo3GVWKVCPrX8--

这里的"----ZcyOpenBoundaryEEpIo3GVWKVCPrX8"是规范中定义的boundary。http传输的内容通过boundary进行了分割,以--${boundary}开始,并以${boundary}--结尾。

明白了以上内容,我们再来看如何使用multipart/form-data进行文件上传。以HttpClient为例进行说明,其他工具大同小异。首先想到的就是要配置 http请求头信息中的Content-Type字段,没错,我们来看如何进行设置:

httpPost.addHeader("Content-Type", "multipart/form-data; boundary=----ZcyOpenBoundaryEEpIo3GVWKVCPrX8");

注意,这里multipart/form-data 后面要跟上boundary。当然,我们也可以不进行Content-Type设置,一般工具都会为我们自动生成规范的Content-Type,自动生成过程不在本次讨论范围内,读者可以自行阅读代码。

继续,我们设置了请求头中的boundary以后还要确保与代码片段1中的boundary保持一致,否则服务端无法读取到请求体信息。服务端正常情况下收到的请求是下面的样子:

当然,上图是以Spring框架为例,其他框架或语言亦大同小异。

那么怎么保证请求头中的boundary与代码片段1中的boundary一致呢?一种办法是模拟http请求手写拼接报文:

String BOUNDARY = "----ZcyOpenBoundaryEEpIo3GVWKVCPrX8";StringBuffer sb = new StringBuffer();// 发送字段for(int i=0; i  sb = sb.append("--");  sb = sb.append(BOUNDARY);  sb = sb.append("\r\n");  sb = sb.append("Content-Disposition: form-data; name=\""+ props[i] + "\"\r\n\r\n");  sb = sb.append(URLEncoder.encode(values[i]));  sb = sb.append("\r\n");}// 发送文件:sb = sb.append("--");sb = sb.append(BOUNDARY);sb = sb.append("\r\n");sb = sb.append("Content-Disposition: form-data; name=\"1\"; filename=\"1.txt\"\r\n");sb = sb.append("Content-Type: application/octet-stream\r\n\r\n");byte[] data = sb.toString().getBytes();byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();// 设置HTTP头hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length + end_data.length));// 输出output = client.openOutputStream();output.write(data);output.write(file);output.write(end_data);......

当然以上方式比较原始,容易出错,我们更喜欢用高级语言。下面还是以HttpClient为例:

String result = "";String boundary ="----ZcyOpenBoundaryEEpIo3GVWKVCPrX8";try (CloseableHttpClient httpClient = HttpClients.createDefault()){    String fileName = file.getName();    HttpPost httpPost = new HttpPost(url);    //设置请求头    httpPost.setHeader("Content-Type","multipart/form-data; boundary="+boundary);    MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.STRICT, boundary, Charset.defaultCharset());        ...省略内容...        httpPost.setEntity(multipartEntity);    // 执行提交    HttpResponse response = httpClient.execute(httpPost);    if (response.getStatusLine().getStatusCode() == 200) {      //响应      HttpEntity responseEntity = response.getEntity();      if (responseEntity != null) {          // 将响应内容转换为字符串          result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));      }        }    } catch (IOException e) {    e.printStackTrace();} catch (Exception e) {    e.printStackTrace();} System.out.println("result=" + result);

注意,上述代码中除了设置header头中的boundary外,还要同时设置MultipartEntity对象中的boundary,这样就保持一致啦。

至此,服务端已经可以获取到期待已久的文件流信息了。

formdata上传文件_关于multipart/formdata上传文件相关推荐

  1. python表单提交文件_python3做multipart/form-data上传请求

    http协议本身的原始方法不支持multipart/form-data请求,这个请求由原始方法演变而来的.multipart/form-data的基础方法是post,也就是说是由post方法来组合实现 ...

  2. python urllib3 上传大文件,python urllib3 multipart/form-data 的坑

    python urllib3 multipart/form-data 的坑 ################################3.上传文件时带了个header与urllib3.reque ...

  3. ashx获取input file 文件_通过Ajax方式上传文件(input file),使用FormData进行Ajax请求...

    一直以来上传文件都使用的是别人的组件,今天看下无刷新上传内部具体的做法.上传文件可以使用form的形式来上传,也可以通过构造formData使用ajax来上传文件: 上传图片 $(function ( ...

  4. node给java发送文件_如何实现node上传文件到后台?

    我在本地有一个主机,装了node,然后要把这个主机的一些监控视频或者其他文件上传到服务器,用的是post去请求java接口,这个怎么实现 function httpPost (url, params, ...

  5. tomcat temp 大量 upload 文件_问题:JavaWeb中实现文件上传的方式有哪些?

    问题:JavaWeb中实现文件上传的方式有哪些? 上回我们说了下文件下载的方式有哪些,这次我们从不同的环境下简单来说说文件上传的方式有哪些. 文件上传的方式 Servlet2.5 方式 Servlet ...

  6. java注解接收上传文件_SpringMVC 处理 multipart/data 请求实现文件上传

    此前我们介绍过 HTTP 的 multipart/form-data 请求: 通过 multipart/form-data 请求可以方便的实现客户端到服务端的文件上传服务,但是默认的 Dispatch ...

  7. 检查文件上传完成_“我的数据上传NCBI又报错了...” “攻略拿去!”

    在上一期的内容中,我们分享了NCBI测序数据上传的主要步骤和资料填写的注意事项.今天跟大家分享最后一步:原始测序数据的上传以及上传后项目编号的相关类型和含义. 图1 NCBI测序数据上传步骤 | 原始 ...

  8. 怎么样向云服务器上传文件_向云服务器上传文件以及移动到指定文件夹

    向云服务器上传文件以及移动到指定文件夹 一.上传文件到云服务器 1. 打开 CuteFTP ,服务器 IP 地址设置为 101.227.245.9 .用户名和密码为空,端口 21 ,点击连接: 出现对 ...

  9. 如何向icloud上传文件_怎样用icloud把手机文件传到电脑上?

    在苹果手机升级到ios11后,就可以用icloud把手机文件传到电脑上了,为此,首先在电脑上下载电脑版icloud并安装.安装完成之后,登陆你的苹果手机ID,然后点击"开始",把鼠 ...

最新文章

  1. Unix/Linux IPC及线程间通信总结
  2. struts2学习笔记之十一:struts2的类型转换器
  3. 第四节:教你如何快速让浏览器兼容ES6特性
  4. java 异常怎么划分_java异常的分类
  5. Python破解百度翻js代码
  6. iPhone、iPad明年或采用USB-C接口;虎牙回应央视点名网课内容充斥广告;Rust 1.44.0 发布| 极客头条...
  7. 360服务器已停止响应,对于 SQL Server 2017年累积更新 5
  8. Spring使用XML的方式实现AOP的开发——Spring AOP(六)
  9. Iris数据集免费下载
  10. android ui设计灵感,26款高品质 APP UI原型设计灵感
  11. 计算机io设备是cpu控制的吗,I/O控制器及控制方式,了解一下
  12. 爬虫练习三:爬取链家二手房信息
  13. asp毕业设计——基于asp+sqlserver的英语网络考试系统设计与实现(毕业论文+程序源码)——网络考试系统
  14. AVC编码中的规格 :High、Baseline、Main什么意思?还有High@L3.0、High@L4.0、High@L5.1等
  15. 学数答题160912-导数极值点偏移
  16. python 卡方分布值_python数据分析探索变量之间的关系
  17. openfalcon 组件监控_使用滴滴云快速搭建 Open-Falcon 监控平台
  18. yaffs2的补丁文件patch-ker分析
  19. 百度地图只显示你想要的部分
  20. 知乎热议:27岁没文凭、想自学编程,有机会成为程序员吗?互联网风口一去不复返了?

热门文章

  1. oauth2.0 php简化模式,OAuth2.0学习(1-5)授权方式2-简化模式(implicit grant type)
  2. execel公式 java工具_PAP-快速开发框架:JAVA 计算器 自定义公式 解决EXCEL计算公式问题...
  3. 二进制权值计算 lsb_2020年二级计算机基础知识备考(第二章)
  4. 快递下单后取消订单_网约车定位地点不动,男子别的平台下单,没取消订单要付6.6元...
  5. 支持向量机SVM的python实现
  6. Python判断变量类型
  7. python中序列(列表list和元组tuple)的用法
  8. PyTorch框架学习十三——优化器
  9. 小甲鱼 OllyDbg 教程系列 (十三) : 把代码和变量注入程序 以及 硬件断点
  10. SpringBoot 自带工具类~StreamUtils