《ASP.NET本质论》大文件上传

来源:互联网 发布:zip在linux下解压 编辑:程序博客网 时间:2024/05/17 09:42

原文地址:http://blog.csdn.net/sky1069/article/details/6660396

        在网站中,上传文件到服务器是一个开发中常见的问题。在ASP.NET 2.0中,还提供了一个FileUpload控件,可以更加简单地完成文件上传的工作。但是,在上传一个比较大的文件时,就会发现上传文件失败了。

-----文件上传的规范
        通过浏览器上传文件的标准是在RFC1867中定义的,RFC1867在HTTP协议的基础上,为input元素增加了type="file"的属性,相应地,在form表单中使用这种input的时候,表单的method必须为post方式,同时表单的enctype也必须设置为multipart/form-data,如下图所示:

[csharp] view plaincopy
  1. <form method="post" action="Default.aspx" id="form1" enctype="multipart/form-data">  
  2.     <input type="file" name="FileUpload1" id="FileUpload1" />  
  3.     <input type="submit" name="Button1" value="Button" onclick ="uploadProgeress();" id="Button1" />  
  4. </form>  

对浏览器来说,type属性为file的input元素将会显示为一个文本框和一个浏览文件的按钮。
当选中文件后,提交表单的时候,被选中的文件将随着此次请求发送到服务器。
表单的enctype属性默认为application/x-www-form-urlencoded。在这种方式下,参数之间通过&符号进行分隔,由于在上传文件的时候,文件中也可能包含&符号,因此,不能使用默认的application/x-www-form-urlencoded方式,enctype必须设置为multipart/form-data方式。
在multiparty/form-data方式下,HTTP Request也会有一些变化
首先,在请求头的Content-Type中除了说明使用multiparty/form-data方式以外,增加了boundary的说明,boundary用来说明请求参数之间的分隔边界,boundary中的数字字符区是随机生成的。

以前的content-type头如下:
content-type:application/x-www-form-urlencoded
改变后的content-type头如下:
Content-Type: multipart/form-data;
boundary=---------------------------27870960

其中boundary的实际内容是由浏览器生成的,并不一定与上面相同。
其次,在请求的数据实体部分有了更多的变化。上传文件内容也就是HTTP实体中的参数的一部分。参数之间通过boundary进行分割,HTTP的实体看起来将是下面的样子:
Content-Type: multipart/form-data; boundary=---------------------------27870960128323


Content-Length: 415


-----------------------------27870960128323


Content-Disposition: form-data; name="FileUpload1"; filename="phone.txt"


Content-Type: text/plain


520630   805058548  ·¶Ã·Áá


520616   1192088350 лÕñ¶«


520618   649798842 Ðí¹úîÈ


593174 ÕÅ·É 116314032


-----------------------------27870960128323


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



Button


-----------------------------27870960128323--


       通过boundary分隔的是可以可以被分成多个部分,每一部分又可以被分割成两部分,说明部分和数据部分。说明部分和数据部分通过连续的两个回车换行进行分隔。
对于普通参数来说,在说明部分将会包括name参数,说明参数的名字。数据部分将是参数的值。
对于上传文件来说,在说明部分将会增加filename参数和Content-Type参数,在这两个参数之后,通过连续的两个回车换行分隔,一直到下一个分隔符志气啊,即为上传文件的内容。

---------------ASP.NET中的文件上传

        在ASP.NET 1.1中,文件上传过程中将被全部保存在内存,对于大文件来说,会造成内存空间的过度使用,可能会招致恶意攻击。为了解决这个问题,ASP.NET在配置文件中提供了一个参数来控制上传文件的尺寸,这个配置参数在system.web元素的子元素 httpRuntime元素中。maxRequestLength属性用来设置允许的最大请求长度,这个参数的单位是KB(字节),默认情况下,参数的值为4096,也就是最大能上传大约4M大小的文件。如果希望上传10M文件,可以对其进行修改为 10240
         在ASP.NET 2.0之后,上传的文件可以缓存到文件中,以减少对内存的消耗。httpRuntime元素提供了一个新的配置参数requestLengthDiskThreshold属性,用来设置一个上传文件尺寸的门槛,超过这个门槛后,请求的内容将会保存到文件中。这个参数的单位也是KB,默认为80,这个值不应该超过 maxRequestLength参数。
       当请求的内容长度超过门槛的限值之后,请求的内容将会被保存到文件中,这个文件的位置由compilation配置元素的tempDirectory属性指定。
       默认情况下,这个参数的值为空串。临时文件将会被保存在 %FrameworkInstallLocation%\TemporaryASP.NET 文件夹下。在Windows 7 下使用开发服务器的时候,临时文件会保存在 c:Users\用户名\AppData\Local\Temp\Temporary ASP.NET Files\下面
         在ASP.NET 2.0之后,知道ASP.NET 4.0 ,当使用 multipart/form-data方式的请求时,ASP.NET会将请求的Post数据通过System.Web.HttpRawUploadedContent进行管理,这是一个内部类,我们不能直接使用,HttpRequest的私有成员 _rawContent将指向这样一个对象实例。
       虽然有了很大的改进,但是,对于大型文件的上传,我们并不能掌握上传的进度,在AJAX中,就难以显示一个动态的上传进度条,不能提供给用户一个友好的上传进程反馈。我们可以自定义一个文件上传的管理器来完成这个功能。

文件上传的解决方案
       在ASP.NET中,浏览器的请求数据到达ASP.NET网站后,被包装为一个内部的对象HttpWorkerRequest,从客户端发送到服务器的数据在内部通过这个对象来读取,HttpRequest提高哦你过了好怎对请求数据的包装,从ASP.NET 2.0开始,在上传文件过程中,上传的数据通过HttpRawUploadedContent对象来表示,这是HttpRequest的一个内部成员,可以通过HttpRequest还没有读取上传文件的情况下,接管ASP.NET对请求参数的读取过程,自定义针对文件上传的处理,实现上传文件的管理。
      对于其他的Post数据,可以通过反射来构建一个模拟的HttpRawUplaodedContent对象实例,提供给HttpRequest使用,保证在候机的处理中正常获取表单数据,

-------------------通过HttpModule接管请求参数
       在文件上传过程中,ASP.NET架构的底层会肚脐HTTP请求中的信息,在系统内部创建一个类型为HttpRawUploadedContent的对象来表示请求参数,这个对象被HttpRequest对象所使用。
      为了接管HttpRequest对请求参数的处理,我们注册HttpApplication的最早的事件BeginRequest,然后将读取的数据保存到一个自定义的对象中。为了能后在后继的处理过程中继续通过HttpRequest来访问请求数据,我们创建一个伪造的HttpRawUploadedContent提供给HttpRequest对象使用。

0 0
原创粉丝点击