`
xixinfei
  • 浏览: 414041 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

http 协议上传文件multipart form-data boundary 说明

    博客分类:
  • web
阅读更多

含义 ENCTYPE="multipart/form-data" 说明:
通过 http 协议上传文件 rfc1867协议概述,jsp 应用举例,客户端发送内容构造

1、概述在最初的 http 协议中,没有上传文件方面的功能。 rfc1867 (http://www.ietf.org/rfc/rfc1867.txt) 为 http 协议添加了这个功能。客户端的浏览器,如 Microsoft IE, Mozila, Opera 等,按照此规范将用户指定的文件发送到服务器。服务器端的网页程序,如 php, asp, jsp 等,可以按照此规范,解析出用户发送来的文件。Microsoft IE, Mozila, Opera 已经支持此协议,在网页中使用一个特殊的 form 就可以发送文件。绝大部分 http server ,包括 tomcat ,已经支持此协议,可接受发送来的文件。各种网页程序,如 php, asp, jsp 中,对于上传文件已经做了很好的封装。

2、上传文件的实例:用 servelet 实现(http server 为 tomcat 4.1.24)1. 在一个 html 网页中,写一个如下的form :

<form enctype="multipart/form-data" action="http://192.168.29.65/UploadFile" method=post> 
load multi files :<br>   
<input name="userfile1" type="file"><br>  
<input name="userfile2" type="file"><br>
<input name="userfile3" type="file"><br>    <input name="userfile4" type="file"><br>  
text field :<input type="text" name="text" value="text"><br>  
<input type="submit" value="提交"><input type=reset></form>



用户可以选择多个文件,填写表单其它项,点击“提交”按钮后就开始上传给 http://192.168.29.65/upload_file/UploadFile

这是一个 servelet 程序注意 enctype="multipart/form-data", method=post, type="file" 。根据 rfc1867, 这三个属性是必须的。multipart/form-data 是新增的编码类型,以提高二进制文件的传输效率。具体的解释请参阅 rfc18672. 服务端 servelet 的编写现在第三方的 http upload file 工具库很多。Jarkata 项目本身就提供了fileupload 包http://jakarta.apache.org/commons/fileupload/ 。

文件上传、表单项处理、效率问题基本上都考虑到了。在 Struts 中就使用了这个包,不过是用 Struts 的方式另行封装了一次。这里我们直接使用 fileupload 包。至于Struts 中的用法,请参阅 Struts 相关文档。这个处理文件上传的 servelet 主要代码如下:

public void doPost( HttpServletRequest request, HttpServletResponse response )
{  
    DiskFileUpload diskFileUpload = new DiskFileUpload();    // 允许文件最大长度
    diskFileUpload.setSizeMax( 100*1024*1024 );    // 设置内存缓冲大小
    diskFileUpload.setSizeThreshold( 4096 );    // 设置临时目录  
    diskFileUpload.setRepositoryPath( "c:/tmp" ); 
    List fileItems = diskFileUpload.parseRequest( request ); 
    Iterator iter = fileItems.iterator();    for( ; iter.hasNext(); )
    {   
    FileItem fileItem = (FileItem) iter.next();  
      if( fileItem.isFormField() ) {         // 当前是一个表单项   
    out.println( "form field : " + fileItem.getFieldName() + ", " + fileItem.getString() );   
      } else {      
    // 当前是一个上传的文件      
    String fileName = fileItem.getName(); 
    fileItem.write( new File("c:/uploads/"+fileName) );    
      } 

}}



为简略起见,异常处理,文件重命名等细节没有写出。3、 客户端发送内容构造假设接受文件的网页程序位于 http://192.168.29.65/upload_file/UploadFile.假设我们要发送一个二进制文件、一个文本框表单项、一个密码 框表单项。文件名为 E:\s ,其内容如下:(其中的XXX代表二进制数据,如 01 02 03)abbXXXccc 客户端应该向 192.168.29.65 发送如下内容:


POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive -----------------------------7d33a816d302b6
Content-Disposition:form-data;
name="userfile1";
filename="E:\s"Content-Type:
application/octet-stream abbXXXccc
-----------------------------7d33a816d302b6

Content-Disposition: form-data;

name="text1" foo

-----------------------------7d33a816d302b6

Content-Disposition: form-data;

name="password1" bar

-----------------------------7d33a816d302b6--


(上面有一个回车)此内容必须一字不差,包括最后的回车。

注意:Content-Length: 424 这里的424是红色内容的总长度(包括最后的回车)
注意这一行:Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6

根据 rfc1867, multipart/form-data是必须的.---------------------------7d33a816d302b6 是分隔符,分隔多个文件、表单项。

其中33a816d302b6 是即时生成的一个数字,用以确保整个分隔符不会在文件或表单项的内容中出现。前面的 ---------------------------7d 是 IE 特有的标志。

Mozila 为---------------------------71用手工发送这个例子,在上述的 servlet 中检验通过。




使用POST发送数据

  以POST方式发送数据主要是为了向服务器发送较大量的客户端的数据,它不受URL的长度限制。POST请求将数据以URL编码的形式放在 HTTP正文中,字段形式为fieldname=value,用&分隔每个字段。注意所有的字段都被作为字符串处理。实际上我们要做的就是模拟浏 览器POST一个表单。以下是IE发送一个登陆表单的POST请求:

POST http://127.0.0.1/login.do HTTP/1.0
Accept: image/gif, image/jpeg, image/pjpeg, */*
Accept-Language: en-us,zh-cn;q=0.5
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Length: 28
\r\n
username=admin&password=1234


  要在MIDP应用程序中模拟浏览器发送这个POST请求,首先设置HttpConnection的请求方式为POST:

hc.setRequestMethod(HttpConnection.POST);


  然后构造出HTTP正文:

byte[] data = "username=admin&password=1234".getBytes();

  并计算正文长度,填入Content-Type和Content-Length:

hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
hc.setRequestProperty("Content-Length", String.valueOf(data.length));

  然后打开OutputStream将正文写入:

OutputStream output = hc.openOutputStream();
output.write(data);


  需要注意的是,数据仍需要以URL编码格式编码,由于MIDP库中没有J2SE中与之对应的URLEncoder类,因此,需要自己动手编写 这个encode()方法,可以参考java.net.URLEncoder.java的源码。剩下的便是读取服务器响应,代码与GET一致,这里就不再 详述。

  使用multipart/form-data发送文件

  如果要在MIDP客户端向服务器上传文件,我们就必须模拟一个POST multipart/form-data类型的请求,Content-Type必须是multipart/form-data。

  以multipart/form-data编码的POST请求格式与application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP请求头设置一个分隔符,例如ABCD:

hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD");

  然后,将每个字段用“--分隔符”分隔,最后一个“--分隔符--”表示结束。例如,要上传一个title字段"Today"和一个文件C:\1.txt,HTTP正文如下:

--ABCD
Content-Disposition: form-data; name="title"
\r\n
Today
--ABCD
Content-Disposition: form-data; name="1.txt"; filename="C:\1.txt"
Content-Type: text/plain
\r\n
<这里是1.txt文件的内容>
--ABCD--
\r\n


  请注意,每一行都必须以\r\n结束,包括最后一行。如果用Sniffer程序检测IE发送的POST请求,可以发现IE的分隔符类似于 ---------------------------7d4a6d158c9,这是IE产生的一个随机数,目的是防止上传文件中出现分隔符导致服务器 无法正确识别文件起始位置。我们可以写一个固定的分隔符,只要足够复杂即可。

  发送文件的POST代码如下:

String[] props = ... // 字段名
String[] values = ... // 字段值
byte[] file = ... // 文件内容
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔符
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 = hc.openOutputStream();
output.write(data);
output.write(file);
output.write(end_data);
// 读取服务器响应:
// TODO...

关于 Content-Type:application/x-www-form-urlencoded 和 Content-Type:multipart/related

最近项目中用到的一个是用一个页面接收c程序post过来的一断字符串..总接收不到值...

我用C#写一个测试可以正常接收到值.

最后抓包比较

 

区别只是
Content
-Type:application/x-www-form-urlencoded

Content
-Type:multipart/related

查资料得:

 application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。 multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。 text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
 补充
form 的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form- data,默认为application/x-www-form-urlencoded。 当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1& amp;name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。

boundary  是客户端浏览器随机生成的
你可以不用提取。
提交数据的时候设置一个串给他
并用该串来分隔数据
就可以了

分享到:
评论

相关推荐

    解决java enctype multipart form-data文件上传传值问题

    ### 解决Java enctype "multipart/form-data" 文件上传传值问题 在Java Web开发中,处理文件上传是一项常见的任务。特别是当涉及到使用`multipart/form-data`作为表单的编码类型时,这种需求更为突出。本文将深入...

    C#使用multipart/form-data示例

    在提供的压缩包文件"C#_multipartform_data示例"中,可能包含了这样的示例代码,我们可以从中学习如何在C#环境中实现文件上传或其他多部分数据传输。 通过理解以上知识点和查看示例代码,我们可以深入理解`...

    C# http系列之以form-data方式上传多个文件及键值对集合到远程服务器

    C# http系列之以form-data方式上传多个文件及键值对集合到远程服务器是指在C#中使用http协议以form-data方式上传多个文件及键值对集合到远程服务器的技术。这种技术广泛应用于云端应用、第三方应用平台、开发平台等...

    基于form-data请求格式详解

    form-data请求格式是HTTP协议中用于上传文件或其他二进制数据的一种请求内容类型。它基于POST方法,其核心特点是可以通过定义boundary(边界)字符串来区分请求中的多个部分。这种格式被广泛应用于表单上传文件的...

    在 Android 上通过模拟 HTTP multipart/form-data 请求协议信息实现图片上传

    在Android平台上,实现图片上传通常涉及使用HTTP协议中的multipart/form-data请求类型,这是处理表单数据,特别是上传文件的标准方式。multipart/form-data允许我们在请求体中包含多个部分,每个部分可以是不同的...

    用C语言编写multipart/form-data实现上传文件

    multipart/form-data是一种HTTP协议中用于处理多部分数据的格式,通常用于上传文件。 在C语言中实现这个功能需要理解HTTP协议的基本原理,特别是POST请求和multipart/form-data的格式。multipart/form-data允许在一...

    http post上传文件与表格 ContentType = multipart/form-data

    "multipart/form-data"是HTTP协议中一种特殊的Content-Type,专为处理混合类型的数据,如文本、文件等。这个Content-Type允许在同一个POST请求中上传多个部分,每个部分可以是不同的数据类型。 当我们需要在HTTP ...

    python处理multipart/form-data的请求方法

    在Python的网络编程中,处理HTTP请求是常见的任务,尤其是涉及到文件上传时,multipart/form-data是一种标准的HTTP请求格式。本文将详细介绍如何使用Python的requests库处理multipart/form-data类型的请求。 首先,...

    Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)

    在HTTP协议中,Multipart/form-data是一种特定的数据编码方式,主要用于文件上传。这种格式通过定义"boundary"(分隔符)来分隔数据的多个部分,每部分由一系列的头部信息和数据体组成。 2. Post方法与Multipart/...

    Python发送form-data请求及拼接form-data内容的方法

    网上关于使用python 的发送multipart/form-data的方法,多半是采用 ulrlib2 的模拟post方法,如下: import urllib2\nboundary='-------------------------7df3069603d6' data=[] data.append('--%s' % boundary) ...

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

    在Web开发中,当涉及到通过HTTP协议向服务器发送POST请求时,我们经常需要选择不同的数据编码类型,主要是`application/x-www-form-urlencoded`和`multipart/form-data`。这两种编码方式各有其适用场景,主要取决于...

    http/formdata

    multipart/form-data的数据由多个part组成,part间通过boundary分隔符进行分割,每个part由header和content组成 multipart/form-data的格式大致为: ----------------------------904587217962624105581666 ...

    java map转Multipart/form-data类型body实例

    在Java开发中,时常需要将一些数据以表单形式上传到服务器,比如使用`multipart/form-data`编码类型。表单数据通常由一些文本字段和文件字段组成,而当我们想将Java中的`Map`对象转换为这种格式时,就需要进行一系列...

    mongoose.c编写多表单域(多input项)文件上传示例代码

    &lt;form action="/upload" method="post" enctype="multipart/form-data"&gt; &lt;!-- 可以有更多input文件域 --&gt; 上传" /&gt; &lt;/form&gt; ``` 在服务器端,我们需要注册一个处理`/upload`路径的回调函数。在这个回调中,...

    form-data-body:一个微小的,无依赖的节点模块,用于为POST请求生成表单的multipartform-data主体

    一个很小的,无依赖的节点模块,用于为POST请求生成表单的multipart / form-data主体。 这意味着它是一个简单的,没有多余的装饰的模块,用于生成要作为POST请求的主体发送的字符串,以模拟表单提交。 如果您需要...

    常见的四种POST 提交数据方式(小总结)

    2. **multipart/form-data**:当需要上传文件时,表单的`enctype`属性应设为`multipart/form-data`。这种方式将数据分割成多个部分,每个部分都有一个边界标识,这样可以同时发送文本和二进制数据(如图片)。每个...

    java模拟发送form-data的请求方式

    Form-Data 是一种常见的 HTTP 请求体格式,广泛应用于文件上传、表单提交等场景。下面是 Java 模拟发送 Form-Data 的请求方式的详细介绍。 什么是 Form-Data Form-Data 是一种 MIME 类型,用于描述表单数据的格式...

    解决springboot 获取form-data里的file文件的问题

    解决 Spring Boot 获取 Form-Data 里面的 File 文件的问题需要在客户端上传文件时添加 filename="..." 部分,并在 Spring Boot 服务器端添加对 filename="..." 部分的处理。这样可以确保 Spring Boot 正确地解析 ...

Global site tag (gtag.js) - Google Analytics