Web上传大文件的三种解决方案
WCF实现大文件上传

WCF实现⼤⽂件上传⼀.⽂件服务接⼝1.⽂件上传2.⽂件传输(上传按钮)3.⽂件传输停⽌服务地址:在客端添加服务器引⽤,从⽽实现客户端调⽤服务器的功能。
⼆.契约服务契约[ServiceContract]:定义服务器这边的功能。
操作契约[OperationContract]:简单的说,就是指定服务器的功能⽅法是否可以被客户端调⽤,如果服务器⽅法未添加操作契约,则⽆法被客户端那边调⽤。
数据契约[DataContract]:和操作契约类似,只不过操作契约作⽤的对象是⽅法,数据契约作⽤的对象是基本类型数据,主要是数据成员或者属性。
回调契约CallbackContract:⽐如说,客户端完成⼀个功能,需要告诉服务端,这就需要向服务器回调⼀个消息,此时就需要定义⼀个回调契约(也就是⼀个接⼝)。
三.创建项⽬⾸先,新建⼀个【WCF服务库】,然后在CRMServer中把系统⾃⼰添加的IService和Service删除,再添加⼀个【WCF服务】,最后添加⼀个窗体应⽤程序,作为客户端,如下:服务器端⽣成的配置⽂件:<?xml version="1.0" encoding="utf-8" ?><configuration><appSettings><add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/></appSettings><system.web><compilation debug="true"/></system.web><!-- 部署服务库项⽬时,必须将配置⽂件的内容添加到主机的 app.config ⽂件中。
System.Configuration 不⽀持库的配置⽂件。
大文件上传解决方案

大文件上传解决方案大文件上传解决方案在现代的Web应用中,上传文件是非常常见的功能之一。
每天都有大量的文件被上传到服务器上,这其中可能包含着各种各样的文件,如照片、视频、音频文件等。
对于小文件的上传,我们可以很方便地使用HTTP协议进行传输。
然而,当文件变得非常大时,传输文件就变得非常困难。
本文将介绍几种常见的大文件上传解决方案,以及它们的优缺点。
1. 分片上传分片上传是一种将大文件进行切割,分成小块进行上传的解决方案。
这种方式可以解决大文件上传的问题,因为分片上传可以将大文件切割成多个小块进行上传,从而减小了每个请求的数据量。
在这种方案中,客户端将文件分为多个部分,并使用多个HTTP请求将这些部分分别上传到服务器上。
服务器接收到这些分片后,可以将它们组合成完整的文件。
优点:- 分片上传可以提高文件上传的可靠性。
因为上传文件的过程被切割成多个小步骤,如果某个分片上传失败,只需要重新上传该分片即可,而不需要重新上传整个文件。
- 分片上传可以提高上传的速度。
由于可以同时上传多个分片,大文件可以以并行的方式上传,从而提高上传速度。
缺点:- 分片上传需要额外的处理逻辑。
服务器需要将各个分片进行组合,这可能需要额外的处理开销。
- 分片上传需要维护上传的状态。
服务器需要追踪每个分片的上传状态,这可能增加了服务器的负担。
2. 断点续传断点续传是一种将上传过程分为多个步骤,并且可以在上传过程中进行暂停、继续的解决方案。
这种方式可以解决因为网络不稳定或者其他原因导致的上传中断的问题,使得文件上传过程更可靠。
优点:- 断点续传可以减少上传过程中的数据重传。
由于可以记录上传的进度,当上传中断后再次继续上传时,只需要上传中断的部分,而不需要重新上传整个文件。
- 断点续传可以提供更好的用户体验。
用户可以在上传过程中随时暂停、继续上传,这样可以更灵活地控制上传的过程。
缺点:- 断点续传需要额外的状态维护。
服务器需要记录每个客户端的上传进度,这可能增加了服务器的负担。
解决文件过大,上传失败的问题——大文件分割分片上传

解决⽂件过⼤,上传失败的问题——⼤⽂件分割分⽚上传⼀、背景 平时在移动和客户端有普通的⽂件上传,但这种⽂件⼤多不⼤,从⼏k到⼏⼗兆,平时完全可以满⾜。
但是对于有些终端系统(pc端、移动端),有时候存在⽂件过⼤,如拍摄的⾼清视频,导出上传不了(内存过⼩或响应时间过长)的问题,⽤户体验及不佳。
这⾥上传不了的原因是前端也是需要将⽂件加载到内存后再上传。
但⽂件过⼤,内存过⼩时问题就⿇烦了。
针对这种情景,特提供⽂件分⽚上传的功能。
不仅可以提⾼上传速率,⽽且对普通和⼤⽂件都适⽤。
并且对于⽂件实现断点续传、秒传的功能。
⼆、解决思路 ⾸先,前端制定分⽚的规则。
⽐如对于⼿机移动端,当上传⽂件⼤于10M时,采⽤分⽚的⽅式上传,并切割⼀⽚就上传,不⽤等待每⽚响应的结果。
对于前端,当前端上传⽂件时,前端边加载的时候边分割⽂件,每分割⼀⽚就上传。
如前端加载完5M就直接上传,完成上传动作后释放上传的那块内存。
防⽌占⽤内存的问题,减少了内存占⽤。
⽽分⽚可以采⽤线程、异步的⽅式,缩短了上传的时间,也解决了⽤户等待时间过长的问题。
对于后端,每次上传的⽂件,获取⽂件的md5值,保存md5值⾄数据库中。
对于完整的⽂件md5值,作为⽂件信息存储;对于分⽚⽂件的md5值,保存在分⽚信息中。
当上传⼀个⽂件时,⾸先是根据完整的md5值查找是否有上传的记录,有则说明上传的⽂件有上传的记录,若成功过直接返回url(⽂件秒传);没有成功过,但有上传记录,则有可能之前上传过部分,则需要继续上传未上传的⽂件(断电续传);没有则按照完整的流程上传。
上传完成后,合并分⽚⽂件,更新并保存信息。
但是在开发的过长中,遇到⼏个问题: ①:对于⽂件md5值,前端如何获取到?因为⽂件md5值是通过⽂件中的内容确定的,每个不同的⽂件md5值是不⼀样的,⽽⽂件本⾝不可能加载全量⽂件再获取的。
②:如何判断⽂件是否全部上传完,并是否可以进⾏合并了? ③:上传的某⽚⽂件若出错了,怎么让该⽚⽂件重新上传? ④:合并⽂件时,如何保证合并的顺序? 针对上述问题,在开发的过程都⼀⼀解决了。
文件上传安全解决方案

文件上传安全解决方案1. 引言随着互联网的快速发展,文件上传功能在各种Web应用中被广泛使用。
然而,恶意的文件上传可能导致严重的安全问题,如代码执行、文件覆盖、服务器资源消耗等。
为了保障Web应用的安全性,本文将介绍一些常见的文件上传安全问题,并提供一些解决方案,以帮助开发者加强文件上传功能的安全性。
2. 常见的文件上传安全问题2.1 文件上传绕过文件上传绕过是指攻击者通过绕过应用程序的文件上传限制,上传恶意文件到服务器上。
常见的绕过方式包括修改文件扩展名、欺骗文件类型检测等。
2.2 文件覆盖文件覆盖发生在攻击者上传一个带有相同文件名的文件到服务器上,从而覆盖掉原有文件。
这可能导致用户数据的丢失或被篡改。
2.3 代码执行文件上传功能中存在的最严重的安全问题之一是远程代码执行。
攻击者可以通过上传恶意文件,并在服务器上执行其中的代码,从而完全控制服务器。
3. 文件上传安全解决方案为了提高文件上传功能的安全性,可以采取以下措施:3.1 文件类型检查在文件上传过程中,首先应检查上传文件的文件类型,并与允许上传的文件类型进行比较。
这可以通过检查文件的扩展名以及文件的头部信息来实现。
服务器端应该在接收到文件后,根据文件类型进行进一步的检查和处理。
3.2 文件大小限制限制上传文件的大小是一种有效的安全措施。
通常,服务器端会设置一个最大文件大小限制,超过该限制的文件将被拒绝上传。
开发者可以在前端对文件大小进行初步检查,并在后端进行进一步验证。
3.3 文件名处理为了防止文件名中包含恶意代码或系统路径,需要对上传的文件名进行过滤和处理。
建议使用白名单机制,只允许特定的字符和格式出现在文件名中。
3.4 文件存储路径将上传的文件保存在一个独立的目录中,并确保该目录不可直接访问。
同时,建议在服务器端生成一个随机的文件名,以避免攻击者根据文件名猜测文件路径。
3.5 文件内容检查除了检查文件类型外,还应对上传的文件内容进行检查。
VUE大文件上传解决方案

VUE⼤⽂件上传解决⽅案需求:项⽬要⽀持⼤⽂件上传功能,经过讨论,初步将⽂件上传⼤⼩控制在500M内,因此⾃⼰需要在项⽬中进⾏⽂件上传部分的调整和配置,⾃⼰将⼤⼩都以501M来进⾏限制。
第⼀步:前端修改由于项⽬使⽤的是BJUI前端框架,并没有使⽤框架本⾝的⽂件上传控件,⽽使⽤的基于jQuery的Uploadify⽂件上传组件,在项⽬使⽤的jslib 项⽬中找到了BJUI框架集成jQuery Uploadify的部分,这部分代码封装在bjui-all.js⽂件中,在bjui-all.js⽂件中的全局变量定义中有以下部分代码,这就是定义的有关于上传的Uploadify控件的重要变量://⽂件上传对象function FileUploader(fileLoc, mgr){var _this = this;this.id = fileLoc.id;this.ui = { msg: null, process: null, percent: null, btn: { del: null, cancel: null,post:null,stop:null }, div: null};this.isFolder = false; //不是⽂件夹this.app = mgr.app;this.Manager = mgr; //上传管理器指针this.event = mgr.event;this.Config = mgr.Config;this.fields = jQuery.extend({}, mgr.Config.Fields, fileLoc.fields);//每⼀个对象⾃带⼀个fields幅本this.State = this.Config.state.None;this.uid = this.fields.uid;this.fileSvr = {pid: "", id: "", pidRoot: "", f_fdTask: false, f_fdChild: false, uid: 0, nameLoc: "", nameSvr: "", pathLoc: "", pathSvr: "", pathRel: "", md5: "", lenLoc: "0", sizeLoc: "", FilePos: "0", lenSvr: "0", perSvr: "0%", complete: false, deleted: false};//json obj,服务器⽂件信息this.fileSvr = jQuery.extend(this.fileSvr, fileLoc);//准备this.Ready = function (){this.ui.msg.text("正在上传队列中等待...");this.State = this.Config.state.Ready;this.ui.btn.post.click(function () {_this.ui.btn.post.hide();_this.ui.btn.del.hide();_this.ui.btn.cancel.hide();_this.ui.btn.stop.show();if (!_this.Manager.IsPostQueueFull()) {_this.post();}else {_this.ui.msg.text("正在上传队列中等待...");_this.State = _this.Config.state.Ready;$.each(_this.ui.btn, function (i, n) { n.hide(); }); _this.ui.btn.del.show();//添加到队列_this.Manager.AppendQueue(_this.fileSvr.id); }});this.ui.btn.stop.click(function () {_this.stop();});this.ui.btn.del.click(function () {_this.stop();_this.remove();});this.ui.btn.cancel.click(function () {_this.stop();_this.remove();//_this.PostFirst();//});};this.svr_error = function (){alert("服务器返回信息为空,请检查服务器配置"); this.ui.msg.text("向服务器发送MD5信息错误");//this.ui.btn.cancel.text("续传");this.ui.btn.stop.hide();this.ui.btn.cancel.show();};this.svr_error_same_name = function () {this.ui.msg.text("服务器存在同名⽂件");this.ui.btn.stop.hide();this.ui.btn.cancel.show();};this.svr_create = function (sv){if (sv.value == null){this.Manager.RemoveQueuePost(this.fileSvr.id); this.svr_error(); return;}if (!sv.ret) {this.Manager.RemoveQueuePost(this.fileSvr.id); this.svr_error_same_name(); return;}var str = decodeURIComponent(sv.value);//this.fileSvr = JSON.parse(str);////服务器已存在相同⽂件,且已上传完成if (plete){this.post_complete_quick();} //服务器⽂件没有上传完成else{this.ui.process.css("width", this.fileSvr.perSvr);this.ui.percent.text(this.fileSvr.perSvr);this.post_file();}};this.svr_update = function () {if (this.fileSvr.lenSvr == 0) return;var param = { uid: this.fields["uid"], offset: this.fileSvr.lenSvr, lenSvr: this.fileSvr.lenSvr, perSvr: this.fileSvr.perSvr, id: this.id, time: new Date().getTime() };$.ajax({type: "GET", dataType: 'jsonp', jsonp: "callback" //⾃定义的jsonp回调函数名称,默认为jQuery⾃动⽣成的随机函数名, url: this.Config["UrlProcess"], data: param, success: function (msg) {}, error: function (req, txt, err) { alert("更新⽂件进度错误!" + req.responseText); }, complete: function (req, sta) { req = null; }});};this.svr_remove = function (){var param = { uid: this.fields["uid"], id: this.fileSvr.id, time: new Date().getTime() };$.ajax({type: "GET", dataType: 'jsonp', jsonp: "callback" //⾃定义的jsonp回调函数名称,默认为jQuery⾃动⽣成的随机函数名, url: this.Config["UrlDel"], data: param, success: function (msg) { }, error: function (req, txt, err) { alert("删除⽂件失败!" + req.responseText); }, complete: function (req, sta) { req = null; }});};this.post_process = function (json){this.fileSvr.lenSvr = json.lenSvr;//保存上传进度this.fileSvr.perSvr = json.percent;this.ui.percent.text("("+json.percent+")");this.ui.process.css("width", json.percent);var str = json.lenPost + " " + json.speed + " " + json.time;this.ui.msg.text(str);};this.post_complete = function (json){this.fileSvr.perSvr = "100%";plete = true;$.each(this.ui.btn, function (i, n){n.hide();});this.ui.process.css("width", "100%");this.ui.percent.text("(100%)");this.ui.msg.text("上传完成");this.Manager.arrFilesComplete.push(this);this.State = plete;//从上传列表中删除this.Manager.RemoveQueuePost(this.fileSvr.id);//从未上传列表中删除this.Manager.RemoveQueueWait(this.fileSvr.id);var param = { md5: this.fileSvr.md5, uid: this.uid, id: this.fileSvr.id, time: new Date().getTime() };$.ajax({type: "GET", dataType: 'jsonp', jsonp: "callback" //⾃定义的jsonp回调函数名称,默认为jQuery⾃动⽣成的随机函数名, url: _this.Config["UrlComplete"], data: param, success: function (msg){_this.event.fileComplete(_this);//触发事件_this.post_next();}, error: function (req, txt, err) { alert("⽂件-向服务器发送Complete信息错误!" + req.responseText); } , complete: function (req, sta) { req = null; }});};this.post_complete_quick = function ()this.fileSvr.perSvr = "100%";plete = true;this.ui.btn.stop.hide();this.ui.process.css("width", "100%");this.ui.percent.text("(100%)");this.ui.msg.text("服务器存在相同⽂件,快速上传成功。
基于Web方式海量数据上传与导入的解决方案

目前这 两种方 法 都存 在 问题 和局 限性 , 严重 阻 碍 各行 各业 的信息化 建设 , 了社 会信 息 化 建设 的一 个 成
严 重 的问题 。 2 .用 WE B方法导 入大容 量数据 的必要性
目前 社会 信息化 程 度在 不 断 提 高 , 离 普 及 各行 但 各 业还 有相 当大 的距离 , 了 满足 人 们对 高生 活 质量 为
It t 进行 的 , 多公 司和 企业 以及 各 政府 、 业 ne 来 me 许 事 单 位都建 立 了 自己பைடு நூலகம் f p 网站 , 基 于 w b的企业 信 - j 及 e 息 化办公 系统 , 这些 网站上 一 般都 有 大 量 的可 供 其 它 企业利 用的共 享资 源 , 中就 有很 多 的大 容量 共 享信 其
第1 7卷第 2期 21 0 0年 6月
长沙民政职业技术学院学报
Ju a fChn sa S ca r ( o rl o a zh o ilWok n
Vo. 7 No 2 11 .
Jl O0 uL2 l
基 于 We b方 式 海 量 数 据 上传 与 导 入 的解 决 方案
谢英辉 邓子 云
(.长沙 民政职业技术学 院,湖南 长沙 4 00 1 104;2 .湖南现代物流职业技术学院 ,湖南 长沙 4 0 3 ) 11 1
[ 摘 要] 作者在文中介绍了传统 方法在解决海量数据从 客户端导 人到服务 器数据库时 的具体 问题 ,提 出了新 的解
决 方案 ,即先利用 A ah 公 司的文件上传组件把文件上传到服务器的临时 目录 ,然后创建扩展名为 “ c ” 的控制文 pce .d 件 ,再利用 j a 言的 se 指令和线程来执行控制文件 、进行数据导人 ,很好地解决 了利用 We a 语 v hl l b来实现大容量数据 的导入 问题 ,具有很高的研究 和应用价值。
关于文件上传大小限制的总结

关于⽂件上传⼤⼩限制的总结 web.config ⽂件的配置:<httpRuntime maxRequestLength="153600" executionTimeout="3600" />150MB ⼀⼩时连接超时以及<basicHttpBinding>节点下⾯<binding ⾥⾯配置maxBufferSize="153600" maxBufferPoolSize="524288" maxReceivedMessageSize="153600"closeTimeout="01:00:00"openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00"配置最⼤字节超时时间2.如果⽤了WCF做⽂件上传:<system.serviceModel><services><!--name 提供服务的类名--><!--behaviorConfiguraron 指定相关的⾏为配置 --><service name="ZRQCommonFile.WCF.FileService"behaviorConfiguration="ZRQCommonFile.WCF.FileServiceBehavior"><!--address - 服务地址--><!--binding - 通信⽅式--><!--contract - 服务契约--><!--bindingConfiguration - 指定相关的绑定配置--><endpointaddress="Message/FileService"binding="basicHttpBinding"contract="ZRQCommonFile.WCF.IFileService"bindingConfiguration="ZRQCommonFile.WCF.FileServiceBehavior" /><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /><host><baseAddresses><add baseAddress="http://localhost:83/WCF/FileService"/></baseAddresses></host></service></services><bindings><basicHttpBinding><!--transferMode - 指⽰通道是使⽤流处理模式还是缓冲模式来传输请求和响应消息--><!--maxReceivedMessageSize - 在采⽤此绑定配置的通道上可接收的最⼤消息⼤⼩(单位:字节)157286400 150MB--> <!--receiveTimeout - 在传输引发异常之前可⽤于完成读取操作的时间间隔--><bindingname="ZRQCommonFile.WCF.FileServiceBehavior"transferMode="Streamed"maxReceivedMessageSize="2147483647"maxBufferSize="2147483647"receiveTimeout="01:00:00" /></basicHttpBinding><wsHttpBinding><!--transferMode - 指⽰通道是使⽤流处理模式还是缓冲模式来传输请求和响应消息--><!--maxReceivedMessageSize - 在采⽤此绑定配置的通道上可接收的最⼤消息⼤⼩(单位:字节)157286400 150MB--> <!--receiveTimeout - 在传输引发异常之前可⽤于完成读取操作的时间间隔--><bindingname="ZRQCommonFile.WCF.FileServiceBehavior"maxReceivedMessageSize="2147483647"receiveTimeout="01:00:00" /></wsHttpBinding></bindings><behaviors><serviceBehaviors><behavior name="ZRQCommonFile.WCF.FileServiceBehavior"><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /><dataContractSerializer maxItemsInObjectGraph="2147483647" /></behavior><behavior name=""><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /></behavior></serviceBehaviors></behaviors><serviceHostingEnvironment multipleSiteBindingsEnabled="true" /></system.serviceModel>3.还有⼀个地⽅会限制到你的上传⼤⼩以及连接时间 IIS ii7.5IIS中有好⼏个地⽅配置⼤⼩的具体的功能不知道,⽹上有这么⼏个1.在《功能视图》有个ASP ⾥⾯有个最⼤请求实体主体限制2.在《功能视图》有个请求筛选右边编辑功能设置允许最⼤内容长度默认是30MB 我多加了⼀个03.上⾯两个都是针对⽹站的下⾯是针对IIS的修改IIS_schema.xml这个⽂件要先获得这个⽂件的控制权;进⼊⽬录C:\Windows\System32\inetsrv\config\schema,修改⽂件IIS_schema.xml 权限:进⼊IIS_schema.xml⽂件权限修改,选择”⾼级”选择”所有者”选中 administrators 确定再进⼊权限编辑,修改administrators 完全控制再去掉IIS_schema.xml的只读属性然后记事本打开⽂件找到 requestLimits ⾥⾯有个attribute name="maxAllowedContentLength" type="uint" defaultValue="30000000"我是增加了⼀个0 300MB 限制。
SpringBoot大文件(百M以上)的上传下载实现技术

SpringBoot⼤⽂件(百M以上)的上传下载实现技术1 背景⽤户本地有⼀份txt或者csv⽂件,⽆论是从业务数据库导出、还是其他途径获取,当需要使⽤蚂蚁的⼤数据分析⼯具进⾏数据加⼯、挖掘和共创应⽤的时候,⾸先要将本地⽂件上传⾄ODPS,普通的⼩⽂件通过浏览器上传⾄服务器,做⼀层中转便可以实现,但当这份⽂件⾮常⼤到了10GB级别,我们就需要思考另⼀种形式的技术⽅案了,也就是本⽂要阐述的⽅案。
技术要求主要有以下⼏⽅⾯:⽀持超⼤数据量、10G级别以上稳定性:除⽹络异常情况100%成功准确性:数据⽆丢失,读写准确性100%效率:1G⽂件分钟级、10G⽂件⼩时级体验:实时进度感知、⽹络异常断点续传、定制字符特殊处理2 ⽂件上传选型⽂件上传⾄ODPS基本思路是先⽂件上传⾄某中转区域存储,然后同步⾄ODPS,根据存储介质可以分为两类,⼀类是应⽤服务器磁盘,另⼀类类是中间介质,OSS作为阿⾥云推荐的海量、安全低成本云存储服务,并且有丰富的API⽀持,成为中间介质的⾸选。
⽽⽂件上传⾄OSS⼜分为web直传和sdk上传两种⽅案,因此上传⽅案有如下三种,详细优缺点对⽐如下:蚂蚁的⽂本上传功能演进过程中对第⼀种、第⼆种⽅案均有实践,缺点⽐较明显,如上表所述,不满⾜业务需求,因此⼤⽂件上传终极⽅案是⽅案三。
3 整体⽅案以下是⽅案三的整体过程⽰意图。
请求步骤如下:1. ⽤户向应⽤服务器取到上传policy和回调设置。
2. 应⽤服务器返回上传policy和回调。
3. ⽤户直接向OSS发送⽂件上传请求。
等⽂件数据上传完,OSS给⽤户Response前,OSS会根据⽤户的回调设置,请求⽤户的服务器。
如果应⽤服务器返回成功,那么就返回⽤户成功,如果应⽤服务器返回失败,那么OSS也返回给⽤户失败。
这样确保了⽤户上传成功,应⽤服务器已经收到通知了。
4. 应⽤服务器给OSS返回。
5. OSS将应⽤服务器返回的内容返回给⽤户。
6. 启动后台同步引擎执⾏oss到odps的数据同步。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Web上传文件的三种解决方案王建斌赵靓(肇庆学院,广东肇庆526061)(肇庆医学高等专科学校,广东肇庆526020)摘要介绍了Web上传文件的三种客户端解决方案:HTML表单、RIA以及插件,它们都可以很好地实现文件上传任务,当然这还需要服务端代码的配合,其中RIA选择了Flex,插件选择了ActiveX作为代表来介绍。
此外,重点在于构建和分析HTTP协议数据来提供大文件上传的实时上传进度显示。
关键词Web;HTTP;Flex;ActiveX;文件上传1引言如果是对于几KB至几MB字节的文件上传,确实没有必要写一篇文章去讨论,但是如果需要上传大文件,例如教师向网络学习系统上传软件、视频等几百MB甚至上GB大小的文件时,平常所用的方法要么失效,要么不能实时反映上传进度。
文中采用的方法对于小文件和大文件上传一视同仁,并且对可能采用的三种解决方案进行展示和总结。
那么,可能采用的三种解决方案如下:(1)HTML Form(可含Javascript、Ajax)。
(2)RIA技术(Flex、Silverlight、JavaFX等)。
(3)插件技术(Acticx、Applet等)。
图1Web服务存储上传文件的方式文件上传到服务器,一般可以存放于本地文件系统、数据库和远程FTP等。
图1为文件上传到Web服务器的存放方式示意图。
浏览器/服务器(B/S)模式,其实是一种特殊形式的C/S,浏览器作为客户端,HTTP作为通信协议。
面对简单的文件上传情况,客户端代码只需HTML表单,服务器编写简单的动态页面和处理代码。
而对于复杂的大文件带进度显示的上传,则一般要深入了解HTTP 1.1协议[1]以及各类技术如何处理HTTP请求。
文中所讲如图2所示的三种解决方案,主要指的是浏览器端的代码,而服务端不限制使用何种动态页面技术或代码模块。
图2浏览器文件上传的三种解决方案2解决方案一:HTML表单建立一个名称为“FileUploadForm.html”的html页面,里面包含一个表单,表单的提交方式为post,enctype 为“multipart/form-data”,action为服务器端处理页面。
此外,form里面还要包含一个文件框,type应为file,示意代码如下:<form action="FileUploadForm.aspx" method="post" enctype="multipart/form-data" name="form1" id="form1"><input type="file" name="fileField" id="fileField" /> …省略部分代码</form>FileUploadForm.aspx 并不难实现, 2.0提供了服务器组件<asp:FileUpload>来协助完成文件上传的任务,并在visual studio中提供可视化的操作极大简化代码的编写工作,并且一次可以同时上传多个文件[2]。
在上传按钮的事件处理方法中,加入下面几行代码,就可以完成文件上传,可以说非常的简单。
protected void uploadButton_Click(object sender,EventArgs e){if (FileUpload1.HasFile){string fileName = Path.GetFileName(FileUpload1. FileName);FileUpload1.PostedFile.SaveAs(Request.Physical ApplicationPath + fileName);Label1.Text = FileUpload1.FileName + "上传完成";}}由于IIS默认允许上传最大长度为4M的文件,所以如果要上传更大的文件,则需要修改web应用程序的web.conf配置文件[3]。
如下修改可以允许最大2G的HTTP请求数据(经作者测试,600多M文件可以成功上传)。
<system.web><httpRuntime executionTimeout="600" maxRequestLength ="2147483647"/></system.web>上传大文件的时候,需要较久的时间,最好可以动态显示上传的进度,可是<asp:FileUpload>组件并不会把接收到的数据立即写入规定文件,也没有提供有关进度的事件。
所以,<asp:FileUpload>组件处理大文件上传显然不合适了,在第四部分我们解决这个问题。
图3是上传进度显示页面,仅实时显示了目前上传文件的数据量。
这是基于一个简单的机制:服务器接收到浏览器提交的HTTP数据后,就把筛选后的数据写入文件。
那么,可以隔一段时间去访问该文件的大小信息,就可以知道上传了多少数据。
图3上传进度显示页面没有显示上传文件的大小,是因为,客户端的Javascript出于安全原因,不能获取文件信息。
而服务端只能获得发送的HTTP正文数据的总长度,而不能直接获取文件的大小,这一点可以得到证实[4](当然,在某些条件下可以通过特殊的方法计算出来)。
3解决方案二:RIA技术RIA技术的倡导者Adobe,提供了Flex技术来使程序员可以用编程的方式生成Flash内容,所以我们使用Flex来开发第二种方案的客户端程序。
其他的RIA技术如Silverlight、JavaFX等也相当有竞争力,不过就运行库而言,Flex是最轻量级的。
上传大文件还不是太复杂的问题,所以Flex已经可以解决的很好。
Silverlight的实现可以参考文献5[5]。
Flex提供FileReference类来方便文件上传,表1是类中最重要的属性、方法和事件[6]。
表1FileReference类的属有了upload方法,上传进度和上传完成事件,可以很容易地实现大文件上传和进度显示任务。
Flash上传的文件大小是没有限制的,经测试,可以上传600多MB的文件。
不过要注意的是,如果该文件需要在Flash 播放器中播放,则最大限制为100MB,所以在上传视频文件且需要在浏览中播放时要注意这个问题。
图4 Flex的文件上传4解决方案三:插件技术在浏览器中使用插件,也可以作为文件上传的一种解决方案,尽管很可能会因为客户浏览器的安全设置,插件无法运行,但是在学校内网、企业内网等环境还是可以考虑使用的。
我们使用VB6开发一个ActiveX控件,可以在IE浏览器中使用。
在VB6中创建一ActiveX控件工程“fileupload”,其中关键部件使用了Winsock控件,用于建立控件与Web服务之间的通信,并且读取文件数据,通过Socket连接把数据以HTTP POST方式发送给服务器[7]。
主要工作如下:(1)建立连接(服务器地址、端口)。
(2)构建HTTP的头部信息,发送给服务器,并打开文件,以准备发送文件数据。
(3)在Winsock的SendProgress事件处理方法中,从文件读取数据到一固定大小缓冲区,然后发送给服务器,此过程重复至文件数据全部读取完成。
(4)接收到服务器发回的“HTTP/1.1 200 OK”,表示文件上传成功。
编写好的控件需要VB打包和部署工具打包好,然后放在Web服务器上,供客户浏览器下载安装,会跳出安全警告提示,以确定是否要安装“fileupload.CAB”,还会提示安装VB运行环境。
图5在浏览器中运行文件上传ActiveX控件的情况,可以清楚显示上传的进度。
图5ActiveX的文件上传5服务端代码前面讲的是文件上传在客户端需要做的工作。
这部分介绍服务端需要做的工作。
Web服务器的选择相比而言很自由,因为客户不关心用什么服务器。
这里主要介绍采用IIS + + C#的组合方式(当然,Tomcat + Servlet + FileUpload也可以实现大文件上传和进度显示,但这里就不介绍了)。
编写一个HTTP Module类来处理HTTP请求数据,该类实现IHttpModule接口,并在BeginRequest事件发生时处理,处理流程的实现在BeginRequestHandler方法中[8]。
public class FileUploadFormModule:IHttpModule{public void Init(HttpApplication app){app.BeginRequest += new EventHandler(BeginRequest Handler);}void BeginRequestHandler(object sender,EventArgs e){// 分析和处理HTTP请求数据}}分析和处理HTTP请求数据的主要工作如下:(1)分析http数据的头部信息,可以得到请求的方法(POST)、url地址、内容长度(Content-Length)、内容类型(Content-Type,boundary)等信息;由于HTTP Module对所有请求都生效,所以在BeginRequestHandler方法中加入下面代码,使得Module只对”FileUploadForm.aspx”的POST请求生效。
if (app.Request.HttpMethod != "POST" || app.Request.Url.Local Path != "/FileUploadForm.aspx")return;(2)根据情况剥掉其他表单数据,保存文件数据。
如果含有filename字段,则可以提取上传的文件名。
如果正文数据即为上传文件内容,则无需分析直接保存即可,因为ActiveX控件可以在HTTP头部信息后直接附上文件数据,而不像浏览器提交表单那样还附加了表单字段数据。
有了HTTP Module,还需要在web.conf中配置,第一个Module可以供前两种解决方案使用,而第二个Module 可以供第三种解决方案使用。
<httpModules><add name="FileUploadFormModule" type= "WebFile Upload. FileUploadFormModule"/><add name="FileUploadActiveXModule" type="Web FileUpload.FileUploadActiveXModule"/></httpModules>6结束语文中的三种解决方案,孰优孰劣,不是本文所讨论的重点。