formdata上传文件_关于multipart/formdata上传文件

最近在做一个文件上传的开放接口,用到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保持一致,否则服务端无法读取到请求体信息。服务端正常情况下收到的请求是下面的样子:

3c750c184dcb2dbd72e5e29f56b3c7f6.png

当然,上图是以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,这样就保持一致啦。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/504340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记】第二章——调度算法:先来先服务FCFS、短作业优先SJF、高响应比HRRN

文章目录一. 先来先服务&#xff08;FCFS&#xff09;二. 短作业优先&#xff08;SJF&#xff09;三. 高响应比优先1. 对前面两种算法的思考2. 描述四. 一、二、三总结例子都要手动写一遍哦&#xff5e;这三个是供早期的批处理系统使用的算法 一. 先来先服务&#xff08;FCFS&a…

【学习笔记】第二章——时间片轮转RR、优先级调度、多级反馈队列调度算法

文章目录一. 时间片轮转二. 优先级调度三. 多级反馈队列调度算法四. 总结一. 时间片轮转 公平&#xff0c;轮流给进程提供时间片只用于进程调度&#xff08;只有进程才能被分配时间片&#xff09;抢占式&#xff0c;由时钟装置发出时钟中断来通知**缺点&#xff1a;**高频的进…

laravel 分词搜索匹配度_elasticsearch基础笔记9-elasticsearch 词项全文搜索

es的核心功能就是搜索和分析。那么我们看看搜索相关内容1、搜索机制在进入搜索之前&#xff0c;会对查询体根据情况进行分析和处理。2、有哪些常用搜索类型全文查询 词项查询 复合查询 嵌套查询 位置查询 特殊查询等。我们常用到的就是前三种&#xff0c;学起来简单&#xff0c…

【学习笔记】第二章——进程同步、进程互斥、进程互斥的硬件/软件实现方法

文章目录一. 进程同步 && 进程互斥四个区域四个原则总结&#xff1a;二. 进程互斥的软件实现方法1&#xff09;单标志法2&#xff09;双标志先检查法3&#xff09;双标志后检查法4&#xff09;Peterson 算法总结三. 进程互斥的硬件实现方法1&#xff09;中断屏蔽方法2&…

python的数据结构包括那些_python算法与数据结构-什么是数据结构

一、什么是数据结构 数据结构&#xff0c;直白地理解&#xff0c;就是研究数据的存储方式。 我们知道&#xff0c;数据存储只有一个目的&#xff0c;即为了方便后期对数据的再利用&#xff0c;就如同我们使用数组存储 {1,2,3,4,5} 是为了后期取得它们的值&#xff0c;因此&…

seo自动发外链_一套节约成本全网营销方案-小小课堂SEO培训教程

很多公司都是由一些小型工作室或个人工作室慢慢发展而来的&#xff0c;在这过程中&#xff0c;人员、资金链、资源、项目等因素一旦出现问题&#xff0c;可能会导致项目失败&#xff0c;那么在互联网上投入的资金如果过多&#xff0c;可能都是白白打了水漂。今天&#xff0c;小…

python 支付宝个人账单_金融支付财务融合业务-实践分享1:订单、账单、交易流水、账套知识解构、原理解析...

本文作者从实际工作实践出发&#xff0c;结合案例等分享了电商金融支付财务融合中的基本概念和相关原理解析&#xff0c;包括&#xff1a;订单、账单、交易流水和账知识解构&#xff0c;供大家一同参考和学习。从事电商、进销存、金融、支付、财务的产品同学&#xff0c;是否对…

【学习笔记】第二章——信号量机制 用信号量实现互斥、同步

文章目录一. 信号量机制整型信号量记录型信号量例子&#xff1a;总结二. 用信号量实现互斥、同步互斥同步前驱总结一. 信号量机制 信号量&#xff1a;一个用于表示系统中某种资源的数量的变量&#xff08;整数 or 记录型变量&#xff09;一对原语&#xff1a;wait(S) 和 signa…

opengl 安装_一步步学OpenGL(34) -《GLFX,一个OpenGL效果库》

教程 34GLFX,一个OpenGL效果库原文&#xff1a; http://ogldev.atspace.co.uk/www/tutorial34/tutorial34.htmlCSDN完整版专栏&#xff1a; https://blog.csdn.net/cordova/article/category/9266966理论介绍这篇教程暂时先不继续探索OpenGL的特性和3D技术了&#xff0c;来介绍…

【LeetCode笔记】剑指 Offer 60. n个骰子的点数(Java、动态规划)

文章目录题目描述代码 & 思路1. 二维数组&#xff08;方便理解&#xff09;2. 一维数组&#xff08;节约空间&#xff09;二刷鸽了好久的打题博客&#xff5e;要继续补起来了&#xff01; 今天不打题&#xff0c;明天变垃圾 QAQ 题目描述 一眼就想先暴力枚举、或者递归呀&…

java 根据圆心计算圆弧上点的经纬度_【控制测量学】-高斯投影正算公式以及java代码

正算公式(将经纬度转化为坐标):java代码(附有源代码和修改后的代码):源代码:/** * 由经纬度反算成高斯投影坐标 * * param longitude * param latitude * return */ public static double[] GaussToBLToGauss( double longitude, double latitude) { …

【LeetCode笔记】剑指 Offer 59 - II. 队列的最大值(Java、辅助队列)

文章目录题目描述思路 && 代码二刷题目描述 恢复打题的第二天打卡&#xff5e; 可以说是这道最小栈的兄弟题目了&#xff0c;很相似总体思路还是一样&#xff0c;靠空间换时间&#xff5e;也就是借助辅助队列 思路 && 代码 这篇题解的动图做得很好&#xff…

redis setnx原子性_不支持原子性的 Redis 事务也叫事务吗?

文章收录在 GitHub JavaKeeper &#xff0c;N线互联网开发必备技能兵器谱 假设现在有这样一个业务&#xff0c;用户获取的某些数据来自第三方接口信息&#xff0c;为避免频繁请求第三方接口&#xff0c;我们往往会加一层缓存&#xff0c;缓存肯定要有时效性&#xff0c;假设我们…

【LeetCode笔记】剑指 Offer 67. 把字符串转换成整数 (Java、字符串)

文章目录题目描述思路 && 代码二刷题目描述 老阅读题了&#xff0c;感觉这道题有点类似写业务接口。 思路 && 代码 首先&#xff0c;把情况划分一下&#xff1a; 非正常值&#xff0c;直接给 0&#xff08;这个实际上可以划分到2的代码中&#xff09;可取…

详细描述三个适于瀑布模型的项目_信息系统项目管理师-第二三章:信息系统项目管理基础与立项管理2...

三、信息系统项目的生命周期1、项目生命周期的定义—项目从启动、组织与准备、执行到结束所经历的一系列阶段2、★项目生命周期的特征①成本与人力投入在开始时较低,在工作执行期间达到最高,并在项目快要结束时迅速回落②风险与不确定性在项目开始时最大,并在项目的整个生命周期…

【LeetCode笔记】剑指 Offer 64. 求1 + 2 + ... + n (Java、限制语法、二刷)

文章目录题目描述思路 && 代码注释版代码&#xff08;方便理解&#xff09;&#xff1a;无注释版代码&#xff08;方便背诵 &#xff09;二刷题目描述 鬼鬼&#xff0c;又到了我最喜欢的戴着脚镣跳舞环节。 讲道理&#xff0c;我觉得这类题应该整个归纳啥的。。&#x…

虚拟dom_从0到1实现一个虚拟DOM

来源 | https://segmentfault.com/a/1190000021331850要构建自己的虚拟 DOM&#xff0c;需要知道两件事。你甚至不需要深入 React 的源代码或者深入任何其他虚拟 DOM 实现的源代码&#xff0c;因为它们是如此庞大和复杂——但实际上&#xff0c;虚拟 DOM 的主要部分只需不到 50…

【LeetCode笔记】剑指 Offer 31. 栈的压入、弹出序列 (Java、栈)

文章目录题目描述代码 && 思路二刷题目描述 打卡第三天&#xff01;加油加油&#xff5e; 数据结构笔试题貌似也会考 &#xff0c;不过考法不一样&#xff0c;有点规律。总的来说还是挺有意思的&#xff0c;我们直接来看代码吧&#xff5e; 代码 && 思路 O(…

【LeetCode笔记】剑指 Offer 20. 表示数值的字符串(Java、字符串)

文章目录题目描述思路 && 代码题目描述 呃…比较恶心的一道题&#xff0c;需要读好题&#xff0c;分完情况再下手有看到dalao用有限状态机来做&#xff0c;不过这边还是直接用了我自己的做法 思路 && 代码 ps&#xff1a;这里没有参考题解的写法&#xff…

【LeetCode笔记】剑指 Offer 16. 数值的整数次方(Java、分治)

文章目录题目描述思路 && 代码二刷题目描述 很棒的题目&#xff01;便于分治思想的理解&#xff01; 思路 && 代码 分情况是大头&#xff5e;递归结束的情况&#xff1a; x0x^0x0 1x1x^1x1 xx−1^-1−1 1 / x 偶数情况&#xff1a;直接二分递归奇数情况…