跨平台应用中如何处理大文件续传的方案总结?

📅 发布时间:2026/7/6 12:23:57 👁️ 浏览次数:
跨平台应用中如何处理大文件续传的方案总结?
最近做在做ePartner项目涉及到文件上传的问题。 以前也做过文件上传但都是些小文件不超过2M。 这次要求上传100M以上的东西。 没办法找来资料研究了一下。基于WEB的文件上传可以使用FTP和HTTP两种协议用FTP的话虽然传输稳定但安全性是个严重的问题而且FTP服务器读用户库获取权限这样对于用户使用来说还是不太方便。 剩下只有HTTP。在HTTP中有3种方式PUT、WEBDAV、RFC1867前2种方法不适合大文件上传目前我们使用的web上传都是基于RFC1867标准的HTML中基于表单的文件上传。协议一、先简要介绍一下RFC1867Form-based File Upload in HTML标准1带有文件提交功能的HTML表单现有的HTML规范为INPUT元素的TYPE属性定义了八种可能的值分别是CHECKBOX, HIDDEN, IMAGE, PASSWORD, RADIO, RESET, SUBMIT, TEXT. 另外当表单采用POST方式的时候表单默认的具有application/x-www -form-urlencoded 的ENCTYPE属性。RFC1867标准对HTML做出了两处修改1为INPUT元素的TYPE属性增加了一个FILE选项。2INPUT标记可以具有ACCEPT属性该属性能够指定可被上传的文件类型或文件格式列表。另外本标准还定义了一种新的MIME类型multipart/form-data以及当处理一个带有ENCTYPE“multipart/form-data” 并且/或含有的标记的表单时所应该采取的行为。举例来说当HTML表单作者想让用户能够上传一个或更多的文件时他可以这么写File to process:HTML DTD里所需要做出的改动是为InputType实体增加一个选项。此外我们也建议用一系列用逗号分隔的文件类型来作为INPUT标记的ACCEPT属性。... 其他元素 ...ENTITY%InputTypeTEXT|PASSWORD|CHECKBOX|RADIO|SUBMIT|RESET|IMAGE|HIDDEN|FILEELEMENTINPUT-0EMPTYATTLISTINPUTTYPE%InputTypeTEXTNAMECDATA#IMPLIED--requiredforallbutsubmitandresetVALUECDATA#IMPLIEDSRC%URI#IMPLIED--forimageinputs--CHECKEDCHECKED#IMPLIEDSIZECDATA#IMPLIED--likeNUMBERS,butdelimitedwithcomma,notspaceMAXLENGTHNUMBER#IMPLIEDALIGNtop|middle|bottom#IMPLIEDACCEPTCDATA#IMPLIED--listofcontenttypes... 其他元素 ...文件传输延迟在某些情况下在确实准备接受数据前服务器先对表单数据中的某些元素比如说用户名账号等进行验证是推荐的做法。但是经过一定的考虑后我们认为如果服务器想这样做的话最好是采用一系列的表单并将前面所验证过的数据元素作为“隐藏”字段传回给客户端或者是通过安排表单使那些需要验证的元素先显示出来。这样的话那些需要做复杂的应用的服务器可以自己维持事务处理的状态而那些简单的应用的则可以实现得简单些。HTTP 协议可能需要知道整个事务处理中的内容总长度。即使没有明确要求HTTP客户端也应该提供上传的所有文件的内容总长度这样一个繁忙的服务器就能够判断文件的内容是否是过大以至于将不能完整地处理从而返回一个错误代码并关闭该连接而不用等到接受了所有的数据才进行判断。目前一些现有的CGI应用对所有的POST事务都需要知道内容总长度。如果INPUT标记含有一个MAXLENGTH属性客户端可以将这个属性值看作是服务器端所能够接受的传送文件的最大字节数。在这种情况下服务器能够在上传开始前提示客户端在服务器上有多少空间可以用来进行文件上传。但是应该引起注意的是这仅仅是一个提示在表单被创建后和文件上传前服务器的实际需求可能会发生改变。在任何情况下如果接受的文件过大的话任何一个HTTP服务器都有可能在文件传输的过程中中断传输。3.传输二进制数据的其他解决办法有些人曾经建议使用一种新的MIME类型aggregate比如说aggregate/mixed 或是content-transfer- encoding “包来描述那些不确定长度的二进制数据而不是靠分解为多个部分来表示。虽然我们并不反对这么做但这需要增加额外的设计和标准化工作来让大家接受并理解aggregate”。 从另一方面来说分解为多部分的机制工作得很好能够非常简单的在客户发送端和服务器接受端加以实现而且能像其他一些综合处理二进制数据的方式一样高效率地工作。4.例子假设服务器段提供的是如下的HTMLWhat is your name What files are you sending用户在“姓名”字段里面填写Joe Blow对问题What files are you sending“用户选择了一个文本文件file1.txt”。客户段可能发送回如下的数据Content-type: multipart/form-data, boundaryAaB03x --AaB03x content-disposition: form-data; namefield1 Joe Blow --AaB03x content-disposition: form-data; namepics; filenamefile1.txt Content-Type: text/plain ... file1.txt 的内容... --AaB03x--如果用户同时还选择了另一个图片文件file2.gif那么客户端可能发送的数据将是Content-type: multipart/form-data, boundaryAaB03x --AaB03x content-disposition: form-data; namefield1 Joe Blow --AaB03x content-disposition: form-data; namepics Content-type: multipart/mixed, boundaryBbC04y --BbC04y Content-disposition: attachment; filenamefile1.txt Content-Type: text/plain ... file1.txt 的内容... --BbC04y Content-disposition: attachment; filenamefile2.gif Content-type: image/gif Content-Transfer-Encoding: binary ... file2.gif的内容... --BbC04y-- --AaB03x--利用RFC1867标准处理文件上传的两种方式1一次性得到上传的数据然后分析处理。看了N多代码之后发现目前无组件程序和一些COM组件都是使用Request.BinaryRead方法。一次性得到上传的数据然后分析处理。这就是为什么上传大文件很慢的原因了IIS超时不说就算几百M文件上去了分析处理也得一阵子。2一边接收文件一边写硬盘。了解了一下国外的商业组件比较流行的有Power-WebAspUpload,ActiveFile,ABCUpload, aspSmartUpload,SA-FileUp。其中比较优秀的是ASPUPLOAD和SA-FILE他们号称可以处理2G的文件SA- FILE EE版甚至没有文件大小的限制而且效率也是非常棒难道编程语言的效率差这么多查了一些资料,觉得他们都是直接操作文件流。这样就不受文件大小的制约。但老外的东西也不是绝对完美ASPUPLOAD处理大文件后,内存占用情况惊人。1G左右都是稀松平常。至于SA-FILE虽然是好东西但是破解难寻。然后发现2款.NET上传组件Lion.Web.UpLoadModule和AspnetUpload也是操作文件流。但是上传速度和 CPU占用率都不如老外的商业组件。做了个测试LAN内传1G的文件。ASPUPLOAD上传速度平均是4.4M/sCPU占用10 -15内存占用700M。SA-FILE也差不多这样。而AspnetUpload最快也只有1.5M/s平均是700K/sCPU占用15- 39测试环境: PIII800,256M内存,100M LAN。我想AspnetUpload速度慢是可能因为一边接收文件一边写硬盘。资源占用低的代价就是降低传输速度。但也不得不佩服老外的程序CPU占用如此之低…三、ASP.NET上传文件遇到的问题我们在用ASP.NET上传大文件时都遇到过这样或那样的问题。设置很大的maxRequestLength值并不能完全解决问题因为ASP.NET会 block直到把整个文件载入内存后再加以处理。实际上如果文件很大的话我们经常会见到Internet Explorer显示 “The page cannot be displayed - Cannot find server or DNS Error”好像是怎么也 catch不了这个错误。为什么因为这是个client side错误server side端的Application_Error是处理不到的。四、ASP.NET大文件上传解决方案解决的方法是利用隐含的HttpWorkerRequest用它的GetPreloadedEntityBody 和 ReadEntityBody方法从IIS为ASP.NET建立的pipe里分块读取数据。Chris Hynes为我们提供了这样的一个方案用HttpModule该方案除了允许你上传大文件外还能实时显示上传进度。Lion.Web.UpLoadModule和AspnetUpload两个.NET组件都是利用的这个方案。方案原理利用HttpHandler实现了类似于ISAPI Extention的功能处理请求Request的信息和发送响应Response。方案要点1 httpHandler or HttpModulea. 在asp.net进程处理request请求之前截获request对象b. 分块读取和写入数据c. 实时跟踪上传进度更新meta信息2 利用隐含的HttpWorkerRequest用它的GetPreloadedEntityBody 和 ReadEntityBody方法处理文件流IServiceProviderproviderIServiceProvider HttpContext.Current;HttpWorkerRequestwrHttpWorkerRequest provider.GetServicetypeofHttpWorkerRequest;byte[]bswr.GetPreloadedEntityBody;....ifwr.IsEntireEntityBodyIsPreloaded{intn1024;byte[]bs2newbyte[n];whilewr.ReadEntityBodybs2,n0{.....}}3 自定义Multipart MIME 解析器自动截获MIME分割符将文件分块写如临时文件实时更新Appliaction 状态ReceivingData, Error, Complete完整示例点击下载完整示例