<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>https://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>https://jackxiang.com/post//</link>
<title><![CDATA[【转】RFC1867协议，用来上传文件的底层。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Mon, 17 Aug 2009 10:06:41 +0000</pubDate> 
<guid>https://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	E文参看：http://www.ietf.org/rfc/rfc1867.txt<br/>中文描述：http://blog.sina.com.cn/s/blog_4c4a58ca0100091l.html<br/>RFC1867协议介绍<br/><br/>RFC1867协议主要是在HTTP协议的基础上为INPUT标签增加了file属性，同时限定了Form的method必须为POST，ENCTYPE必须为multipart/form-data。当然还增加了一些与此相关属性，但都不是很重要，我们在此不作讨论。<br/><br/>在一般的基于Web的程序中，我们往往使用&lt;input type=”file”&gt;标签，该标签在被浏览器解析后会产生一个文本框和一个浏览按钮，单击浏览按钮会出现系统的文件选择框。<br/><br/>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行上传及&lt;input type=”file”&gt;标签的一些特性<br/><br/>在上图选择相应的文件，按Upload按钮即可把选择的文件上传到服务器（服务器端可用JspSmartUpload等组件接受文件）。归根结底上传的所有操作都是由浏览器作的，用户所做的只是简单地选择了一下文件而已，接下来的问题是，如何能把一个目录中所有的文件实现一次性上传？<br/><br/>（1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为目录下的文件数量是不定的，因此我们基本不可能通过增加多个&lt;input type=”file”&gt;标签的方式来解决问题。<br/><br/>（2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果在Jsp中我们可以考虑以下方式来解决：通过Jsp动态创建&lt;input type=”file”&gt;标签，并使所创建的标签不可见。把每个标签的Value属性设置为每个文件的路径。在按Upload时再实行一次性上传。在我们试验了之后就会发现，对&lt;input type=”file”&gt;的Value属性赋值是徒劳的行为，因为RFC1867协议并没有要求浏览器的实现者一定实现Value属性，而IE恰好忽略了Value属性。<br/><br/>即以下代码将是徒劳的（IE中）<br/><br/>&lt;script language=”javascript”&gt;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //对Value赋值<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Form1.file1.value=”c:&#92;&#92;aa.txt”;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //执行后，IE将忽略此赋值<br/><br/>&lt;.script&gt;<br/><br/>上述两种方式均无法完成我们需要的功能，接下来我们只能剖析IE是如何完成上传功能，把具体的实现方法用ActiveX或（Applet）来完成。<br/><br/>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HTTP协议的简单介绍<br/><br/>一般说来我们认为HTTP协议是构建在TCP/IP之上的协议，其实HTTP协议本身无此限制，但因现实中多数情况均是如此，我们就姑且如此认为。HTTP数据总体说来分三大部分：<br/><br/>（1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请求行，如下格式<br/><br/>(Request) POST SP URL SP HTTP/1.1 &#92;r&#92;n<br/><br/>请求方法+空格+请求URL+空格+HTTP协议版本+回车换行<br/><br/>如：POST http://localhost:8080/test/test.jsp HTTP1.1&#92;r&#92;n<br/><br/>(Response)HTTP/1.1 SP 200 SP OK &#92;r&#92;n<br/><br/>HTTP协议应答版本+空格+状态码+状态描述+回车换行<br/><br/>如：HTTP/1.1 200 OK &#92;r&#92;n<br/><br/>请求行主要是描述请求的URL，HTTP协议版本，应答状态等信息。<br/><br/>（2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请求头<br/><br/>在HttpServletRequest接口里已经封装了对HTTP头操作的方法。如Content-type，Content-length，User-Agent,Host等都是HTTP头。HTTP头主要描述了HTTP所传输数据的一些信息，如主机，数据内容类型，数据长度，代理类型等。<br/><br/>如：<br/><br/>User-Agent: myselfHttp/1.1&#92;r&#92;n<br/><br/>Accept: www/source; text/html; image/gif; */*&#92;r&#92;n<br/><br/>HTTP头+:+空格+头信息+回车换行<br/><br/>（3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HTTP实体<br/><br/>HTTP实体存放着，HTTP请求的内容，如参数信息，文本框的内容，隐含控件的值，ListBox的值等。如果在页面上存在:<br/><br/>&lt;input type=”text” name=”userName” value=”zhangsan”&gt;<br/><br/>&lt;input type=”password” name=”password” value=”123”&gt;<br/><br/>HTTP实体会出现以下形式：(POST提交)<br/><br/>userName=zhangsan&amp;password=123<br/><br/>GET提交的时候需要解析HTTP请求行中的URL，在此不多作讨论。<br/><br/>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RFC1867协议的数据格式<br/><br/>（1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RFC1867对HTTP头的变更<br/><br/>RFC1867对HTTP头作了适当地变更，但变更很小。首先content-type头由以前的：<br/><br/>content-type: application/x-www-form-urlencoded<br/><br/>变为<br/><br/>content-type: multipart/form-data; +空格+<br/><br/>boundary=---------------------------7d52b133509e2<br/><br/>即增加了boundary，所谓的boundary其实就是分割线，下文将看到，RFC1867利用boundary分割HTTP实体数据。boundary中数字字符区是随机生成的。<br/><br/>（2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对HTTP实体的变更<br/><br/>因为RFC1867增加了文件上传得功能，而上传文件内容自然也会被加入到HTTP的实体中。现在因为既有HTTP一般的参数实体，又有上传文件的实体，所以用boundary把每种实体进行了分割，HTTP的实体看起来将是下面的样子：<br/><br/>-----------------------------7d52b133509e2<br/><br/>Content-Disposition: form-data; name=&quot;file1&quot;; filename=&quot;c:&#92;aa.txt&quot;<br/><br/>Content-Type: text/plain<br/><br/>文件内容在此处<br/><br/>-----------------------------7d52b133509e2<br/><br/>Content-Disposition: form-data; name=&quot;userName&quot;<br/><br/>zhangsan<br/><br/>-----------------------------7d52b133509e2<br/><br/>Content-Disposition: form-data; name=&quot;password&quot;<br/><br/>123<br/><br/>-----------------------------7d52b133509e2—<br/><br/>{关于实体的其他说明：<br/><br/>Content-type: multipart/form-data, boundary=AaB03x<br/><br/>(&#92;r&#92;n)<br/><br/>--AaB03x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //boundary<br/>content-disposition: form-data; name=&quot;user&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//form 表单变量名<br/>(&#92;r&#92;n)<br/>Wilson Peng&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//form 表单变量数据<br/>--AaB03x&nbsp;&nbsp;&nbsp;&nbsp; <br/>content-disposition: form-data; name=&quot;myfile&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //form 表单变量名<br/>Content-type: multipart/mixed, boundary=BbC04y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //新的描述和新的描述和boundary<br/>(&#92;r&#92;n)<br/>--BbC04y<br/>Content-disposition: attachment; filename=&quot;myphoto.gif&quot; //attachment 图片名字<br/>Content-type: image/gif&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //图片描述<br/>Content-Transfer-Encoding: binary&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//编码方式<br/>&nbsp;&nbsp;&nbsp;&nbsp;(&#92;r&#92;n)<br/>(...myphoto.gif)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//图片内容略...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>--BbC04y--<br/>--AaB03x--<br/><br/>}<br/><br/>很明显，增加了文件上传后，HTTP实体变得稍微复杂了，首先是通过boundary把实体分开，以便于读取，然后对FileUpload的格式也作了限制。<br/><br/>（3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RFC1867协议的数据格式<br/><br/>根据RFC1867协议，在HTTP实体中必须对每个上传得文件有说明头，如：<br/><br/>Content-Disposition: form-data; name=&quot;file1&quot;;<br/><br/>filename=&quot;c:&#92;aa.txt&quot;<br/><br/>Content-Disposition:指明内容类型是form-data<br/><br/>name=&quot;file1&quot;:指明页面上&lt;input type=”file”&gt;标签的名字是file1<br/><br/>filename=&quot;c:&#92;aa.txt&quot;:指明上传文件在客户端上的全路径<br/><br/>空行：文件头说明完毕后，要加一空行，以表示后面的数据是文件的内容<br/><br/>文件内容：再接下来就是文件的内容<br/><br/>从这个角度说，完全可以利用HTTP协议+RFC1867协议开发基于文档管理应用程序。<br/><br/>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 协议的实现（客户端）<br/><br/>协议的好处就是，只要你提供的数据符合协议的要求，Server端就可以正确解析你的请求。而不论数据是由IE产生的，或有你自己的Application产生的。通过上面的分析，我们已经基本清楚了RFC1867协议的要求，只要我们打开指定的端口，把数据按照协议的要求写进去就会模拟出IE上传的功能。用程序实现是非常Easy的事。附件将给出Java实现版本，程序只是简单地实现了上传，根据我们前面的分析实现文件上传，参数传递这种稍麻烦的形式也是比较简单的。另外，该程序并没有实现返回数据的解析，同样根据我们前面的分析，按照HTTP协议去解析返回的数据也不是难事。总之，希望本程序能起到抛砖引玉的作用，<br/><br/>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代码实现<br/><br/><br/>1、概述<br/>在最初的 http 协议中，没有上传文件方面的功能。 rfc1867 ( http://www.ietf.org/rfc/rfc1867.txt ) 为 http 协议添加了这个功能。客户端的浏览器，如 Microsoft IE, Mozila, Opera 等，按照此规范将用户指定的文件发送到服务器。服务器端的网页程序，如 php, asp, jsp 等，可以按照此规范，解析出用户发送来的文件。<br/>Microsoft IE, Mozila, Opera 已经支持此协议，在网页中使用一个特殊的 form 就可以发送文件。<br/>绝大部分 http server ，包括 tomcat ，已经支持此协议，可接受发送来的文件。<br/>各种网页程序，如 php, asp, jsp 中，对于上传文件已经做了很好的封装。<br/>2、上传文件的实例：用 servelet 实现（http server 为 tomcat 4.1.24）<br/>1. 在一个 html 网页中，写一个如下的form ：<br/>&lt;form enctype=&quot;multipart/form-data&quot; action=&quot;http://192.168.29.65/UploadFile&quot; method=post&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;load multi files :&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name=&quot;userfile1&quot; type=&quot;file&quot;&gt;&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name=&quot;userfile2&quot; type=&quot;file&quot;&gt;&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name=&quot;userfile3&quot; type=&quot;file&quot;&gt;&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name=&quot;userfile4&quot; type=&quot;file&quot;&gt;&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;text field :&lt;input type=&quot;text&quot; name=&quot;text&quot; value=&quot;text&quot;&gt;&lt;br&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;input type=&quot;submit&quot; value=&quot;提交&quot;&gt;&lt;input type=reset&gt;<br/>&lt;/form&gt;<br/>2. 服务端 servelet 的编写<br/>现在第三方的 http upload file 工具库很多。Jarkata 项目本身就提供了fileupload 包http://jakarta.apache.org/commons/fileupload/ 。文件上传、表单项处理、效率问题基本上都考虑到了。在 struts 中就使用了这个包，不过是用 struts 的方式另行封装了一次。这里我们直接使用 fileupload 包。至于struts 中的用法，请参阅 struts 相关文档。<br/>这个处理文件上传的 servelet 主要代码如下：<br/>public void doPost( HttpServletRequest request, HttpServletResponse response ) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;DiskFileUpload diskFileUpload = new DiskFileUpload();<br/>&nbsp;&nbsp;&nbsp;&nbsp;// 允许文件最大长度<br/>&nbsp;&nbsp;&nbsp;&nbsp;diskFileUpload.setSizeMax( 100*1024*1024 );<br/>&nbsp;&nbsp;&nbsp;&nbsp;// 设置内存缓冲大小<br/>&nbsp;&nbsp;&nbsp;&nbsp;diskFileUpload.setSizeThreshold( 4096 );<br/>&nbsp;&nbsp;&nbsp;&nbsp;// 设置临时目录<br/>&nbsp;&nbsp;&nbsp;&nbsp;diskFileUpload.setRepositoryPath( &quot;c:/tmp&quot; );<br/>&nbsp;&nbsp;&nbsp;&nbsp;List fileItems = diskFileUpload.parseRequest( request );<br/>&nbsp;&nbsp;&nbsp;&nbsp;Iterator iter = fileItems.iterator();<br/>&nbsp;&nbsp;&nbsp;&nbsp;for( ; iter.hasNext(); ) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileItem fileItem = (FileItem) iter.next();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( fileItem.isFormField() ) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 当前是一个表单项<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println( &quot;form field : &quot; + fileItem.getFieldName() + &quot;, &quot; + fileItem.getString() );<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 当前是一个上传的文件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String fileName = fileItem.getName();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileItem.write( new File(&quot;c:/uploads/&quot;+fileName) );<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}<br/>为简略起见，异常处理，文件重命名等细节没有写出。<br/>3、 客户端发送内容构造<br/>假设接受文件的网页程序位于 http://192.168.29.65/upload_file/UploadFile.<br/>假设我们要发送一个二进制文件、一个文本框表单项、一个密码框表单项。文件名为 E:&#92;s ，其内容如下：（其中的XXX代表二进制数据，如 01 02 03）<br/>a<br/>bb<br/>XXX<br/>ccc<br/>客户端应该向 192.168.29.65 发送如下内容：<br/>POST /upload_file/UploadFile HTTP/1.1<br/>Accept: text/plain, */*<br/>Accept-Language: zh-cn<br/>Host: 192.168.29.65:80<br/>Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6<br/>User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)<br/>Content-Length: 424<br/>Connection: Keep-Alive<br/>-----------------------------7d33a816d302b6<br/>Content-Disposition: form-data; name=&quot;userfile1&quot;; filename=&quot;E:&#92;s&quot;<br/>Content-Type: application/octet-stream<br/>a<br/>bb<br/>XXX<br/>ccc<br/>-----------------------------7d33a816d302b6<br/>Content-Disposition: form-data; name=&quot;text1&quot;<br/>foo<br/>-----------------------------7d33a816d302b6<br/>Content-Disposition: form-data; name=&quot;password1&quot;<br/>bar<br/>-----------------------------7d33a816d302b6--<br/>此内容必须一字不差，包括最后的回车。<br/>注意：Content-Length: 424 这里的424是红色内容的总长度（包括最后的回车）<br/>注意这一行：<br/>Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6<br/>根据 rfc1867, multipart/form-data是必须的.<br/>---------------------------7d33a816d302b6 是分隔符，分隔多个文件、表单项。其中33a816d302b6 是即时生成的一个数字，用以确保整个分隔符不会在文件或表单项的内容中出现。前面的 ---------------------------7d 是 IE 特有的标志。 Mozila 为---------------------------71<br/>用手工发送这个例子，在上述的 servlet 中检验通过。<br/>(上面有一个回车)用户可以选择多个文件，填写表单其它项，点击“提交”按钮后就开始上传给 http://192.168.29.65/upload_file/UploadFile 这是一个 servelet 程序<br/>注意 enctype=&quot;multipart/form-data&quot;, method=post, type=&quot;file&quot; 。根据 rfc1867, 这三个属性是必须的。multipart/form-data 是新增的编码类型，以提高二进制文件的传输效率。具体的解释请参阅 rfc1867
]]>
</description>
</item><item>
<link>https://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 【转】RFC1867协议，用来上传文件的底层。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>