关闭

Multipart/form-data POST文件上传详解

标签: 浏览器服务器fileurl网络协议upload
286360人阅读 评论(9) 收藏 举报
分类:

Multipart/form-data POST文件上传详解

理论

简单的HTTP POST

大家通过HTTP向服务器发送POST请求提交数据,都是通过form表单提交的,代码如下:

<form method="post"action="http://w.sohu.com" >

         <inputtype="text" name="txt1">

         <inputtype="text" name="txt2">

 </form>

提交时会向服务器端发出这样的数据(已经去除部分不相关的头信息),数据如下:

 

POST / HTTP/1.1

Content-Type:application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: w.sohu.com

Content-Length: 21

Connection: Keep-Alive

Cache-Control: no-cache

 

txt1=hello&txt2=world

 

对于普通的HTML Form POST请求,它会在头信息里使用Content-Length注明内容长度。头信息每行一条,空行之后便是Body,即“内容”(entity)。它的Content-Type是application/x-www-form-urlencoded,这意味着消息内容会经过URL编码,就像在GET请 求时URL里的QueryString那样。txt1=hello&txt2=world

POST上传文件

最早的HTTP POST是不支持文件上传的,给编程开发带来很多问题。但是在1995年,ietf出台了rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。所以Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此发送post请求时候,表单<form>属性enctype共有二个值可选,这个属性管理的是表单的MIME编码:

 ①application/x-www-form-urlencoded(默认值)
 ②multipart/form-data
其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype="application/x- www-form-urlencoded".

 

通过form表单提交文件操作如下:

<form method="post"action="http://w.sohu.com/t2/upload.do" enctype=”multipart/form-data”>

         <inputtype="text" name="desc">

         <inputtype="file" name="pic">

 </form>

 

浏览器将会发送以下数据:

POST /t2/upload.do HTTP/1.1

User-Agent: SOHUWapRebot

Accept-Language: zh-cn,zh;q=0.5

Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Content-Length: 60408

Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Host: w.sohu.com

 

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="desc"

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: 8bit

 

[......][......][......][......]...........................

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="pic"; filename="photo.jpg"

Content-Type: application/octet-stream

Content-Transfer-Encoding: binary

 

[图片二进制数据]

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

 

我们来分析下数据,第一个空行之前自然还是HTTP header,之后则是Entity,而此时的Entity也比之前要复杂一些。根据RFC 1867定义,我们需要选择一段数据作为“分割边界”( boundary属性),这个“边界数据”不能在内容其他地方出现,一般来说使用一段从概率上说“几乎不可能”的数据即可。 不同浏览器的实现不同,例如火狐某次post的  boundary=---------------------------32404670520626 , opera为boundary=----------E4SgDZXhJMgNE8jpwNdOAX ,每次post浏览器都会生成一个随机的30-40位长度的随机字符串,浏览器一般不会遍历这次post的所有数据找到一个不可能出现在数据中的字符串,这样代价太大了。一般都是随机生成,如果你遇见boundary值和post的内容一样,那样的话这次上传肯定失败,不过我建议你去买彩票,你太幸运了。Rfc1867这样说明{A boundary is selected that does not occur in any of the data. (This selection is sometimes done probabilisticly.)}。

 

 

选择了这个边界之后,浏览器便把它放在Content-Type 里面传递给服务器,服务器根据此边界解析数据。下面的数据便根据boundary划分段,每一段便是一项数据。(每个field被分成小部分,而且包含一个value是"form-data"的"Content-Disposition"的头部;一个"name"属性对应field的ID,等等,文件的话包括一个filename)

  • IE和Chrome在filename的选择策略上有所不同,前者是文件的完整路径,而后者则仅仅是文件名。
  • 数据内容以两条横线结尾,并同样以一个换行结束。在网络协议中一般都以连续的CR、LF(即\r、\n,或0x0D、Ox0A)字符作为换行,这与Windows的标准一致。如果您使用其他操作系统,则需要考虑它们的换行符

 另外Content-length 指的是所用数据的长度。

实现

httpClient4如何实现

httpClient4使用http-mime.jar包的MultipartEntity实现,代码如下(为了简洁,处理了异常处理代码):

                           

HttpPost httpPost = newHttpPost(url);

Log.debug("post url:"+url);

httpPost.setHeader("User-Agent","SOHUWapRebot");

httpPost.setHeader("Accept-Language","zh-cn,zh;q=0.5");

httpPost.setHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.7");

httpPost.setHeader("Connection","keep-alive");

 

MultipartEntity mutiEntity = newMultipartEntity();

File file = new File("d:/photo.jpg");

mutiEntity.addPart("desc",new StringBody("美丽的西双版纳", Charset.forName("utf-8")));

mutiEntity.addPart("pic", newFileBody(file));

 

 

httpPost.setEntity(mutiEntity);

HttpResponse  httpResponse = httpClient.execute(httpPost);

HttpEntity httpEntity =  httpResponse.getEntity();

String content = EntityUtils.toString(httpEntity);

                           

                  

 

参考:

Rfc1867:http://www.ietf.org/rfc/rfc1867

Rfc1867:http://www.vivtek.com/rfc1867.html

 


38
3
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

HTTP协议之multipart/form-data请求分析

首先来了解什么是multipart/form-data请求: 根据http/1.1 rfc 2616的协议规定,我们的请求方式只有OPTIONS、GET、HEAD、POST、PUT、DELETE、T...
  • five3
  • five3
  • 2012-01-06 15:36
  • 183336

文章4:multipart/form-data详细介绍

转载请注明出处 http://blog.csdn.net/yankai0219/article/details/8159701 主要内容 1.什么是Multipart/form-dat...
  • yankai0219
  • yankai0219
  • 2012-11-07 21:35
  • 17923

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

------------------------------------------------------------------大家好,我是许飞,微软拼音的开发实习生。在网络编程中,经常用到从服务...
  • MSPinyin
  • MSPinyin
  • 2011-01-15 11:46
  • 50748

multipart/form-data 文件上传表单中 传递参数无法获取的原因!

multipart/form-data 文件上传表单中 传递参数无法获取的原因!
  • zllww123
  • zllww123
  • 2017-08-25 22:01
  • 1335

利用MultipartFile实现文件上传

利用MultipartFile实现文件上传         在java中上传文件似乎总有点麻烦,没.net那么简单,记得最开始的时候用smartUpload实现文件上传,最近在工作中使用spring的...
  • hbcui1984
  • hbcui1984
  • 2007-01-30 17:38
  • 117806

为什么上传文件的表单需要设置enctype="multipart/form-data"

在学习PHP文件上传的过程中发现,HTML表单需要设置enctype="multipart/form-data"这个属性,虽然不这么设置的确无法上传,但这是为什么呢?
  • mazhibinit
  • mazhibinit
  • 2015-11-05 20:23
  • 11205

multipart/form-data请求与文件上传的细节

要上传文件,需要用post方法,并且设置enctype为multipart/form-data。 form action="/upload" method="post" enctype="m...
  • zshake
  • zshake
  • 2017-09-14 21:45
  • 707

post multipart/form-data 类型表单如何获取File外其他参数

要在Filter中解析原生的request,网上找的都不靠谱,我的应用中在controller层通过Spring完美解析,所以想到了直接使用Spring的原生支持来解决这个问题,终于找到了Common...
  • u012195214
  • u012195214
  • 2017-06-15 23:14
  • 2628

multipart/form-data和application/x-www-form-urlencoded的区别

FORM元素的enctype属性指定了表单数据向服务器提交时所采用的编码类型,默认的缺省值是“application/x-www-form-urlencoded”。     然而,在向服务器发送大量...
  • oqqQuZi1234567
  • oqqQuZi1234567
  • 2015-03-03 16:28
  • 3781

Multipart/form-data文件上传简介

 理论 简单的HTTP POST 大家通过HTTP向服务器发送POST请求提交数据,都是通过form表单提交的,代码如下:               ...
  • honghailiang888
  • honghailiang888
  • 2016-06-20 10:15
  • 1396
    个人资料
    • 访问:1986545次
    • 积分:20344
    • 等级:
    • 排名:第471名
    • 原创:307篇
    • 转载:143篇
    • 译文:9篇
    • 评论:445条
    博客专栏
    最新评论
    感兴趣