2026/4/18 19:18:23
网站建设
项目流程
哪个网站有建设需要等文件,wordpress修改登录,专业网站建设提供商,网站设计公司模板介绍
在Web 程序中上传文件是很常见的需求。利用HTTP 协议上传文件的方式非常有限#xff0c;最常见的莫过于使用 元素进行上传。这种上传方式会将内容使用multipart/form-data 方案进行编码#xff0c;并将内容POST 到服务器端。使用multipart/form-data 编码方式与默认的a…介绍在Web 程序中上传文件是很常见的需求。利用HTTP 协议上传文件的方式非常有限最常见的莫过于使用元素进行上传。这种上传方式会将内容使用multipart/form-data 方案进行编码并将内容POST 到服务器端。使用multipart/form-data 编码方式与默认的application/x-url-encoded 编码方式相比在大数据量情况下效率要高很多。使用上传文件最大的优势在于编程方便几乎各种服务器端技术都对这种上传方式做了良好的封装使得程序员能够直观地对客户端上传的文件进行处理。不过总体来说这个协议并不适合做文件传输解析数据流内容的代价相对较高并且没有一些例如断点续传的机制来辅助导致在上传大文件时经常会力不从心。有朋友认为使用上传文件最大的问题在于内存占用太高由于需要将整个文件载入内存进行处理导致如果用户上传文件太大或者同时上传的用户太多会造成服务器端内存耗尽。这个观点其实是错误的。对于某些服务器端的技术例如Spring Framework 或者早期ASP.NET 1.1 时为了供程序处理都会将用户上传的内容完全载入内存这的确会带来问题。但是其实协议本身并没有规定服务器端应该使用何种方式来处理上传的文件。例如在现在的ASP.NET 2.0 中就已经会在用户上传数据超过一定数量之后将其存在硬盘中的临时文件中而这点对于开发人员完全透明也就是说开发人员可以像以前一样进行数据流的处理。ASP.NET 2.0 启用硬盘临时文件的阈值threshold 是可配置的maxRequestLength 自不必说刚接触ASP.NET 的朋友总会发现上传文件不能超过4M 这就是因为maxRequestLength 的大小默认为4096 这就限制着每个请求的大小不得超过4096KB 。这么做的目的是为了保护应用程序不受恶意请求的危害。当请求超过maxRequestLength 之后ASP.NET 处理程序将不会处理该请求。这里和ASP.NET 抛出一个异常是不同的这就是为什么如果用户上传文件太大看到的并非是ASP.NET 应用程序中指定的错误页面或者默认的因为ASP.NET 还没有对这个请求进行处理。requestLengthDiskThreshold 就是刚才所提到的阈值其默认值为256 即一个请求内容超过256KB 时就会启用硬盘作为缓存。这个阈值理论上和客户端是否是在上传内容无关只要客户端发来的请求大于这个值即可。因此在ASP.NET 2.0 中服务器的内存不会因为客户端的异常请求而耗尽。如果我们需要在ASP.NET 如果没有特别说明以下ASP.NET 均指ASP.NET 2.0 应用中上传文件我们一般就会直接使用控件进行文件上传。如果一个页面中存在控件那么页面中form 元素的enctype 就会被自动改为multipart/form-data 而且我们可以在页面PostBack 之后通过控件的引用来获得客户端通过该控件所上传得文件。不过如果上传文件的功能需要较为特别的需求—— 例如需要进度条提示控件就无能为力了。确切地说应该是所能提供的支持非常有限因此一些特殊需求我们不能实现—— 严格说来应该是无法轻易地、直接地实现。这样在实现这些功能时我们就会绕一个大大的弯。为了避免每次实现相同功能时都要费神费时地走一遍弯路因此出现了各种上传组件。上传组件提供了封装好的功能使得我们在实现文件上传功能时变得轻松了很多。例如几乎所有的上传组件都直接或间接地提供了进度提示的功能有的提供了当前的百分比数值有的则直接提供了一套UI 有的组件只提供了简单的UI 有的却提供了一整套上传、删除的管理界面。此外有的组件还提供了防止客户端恶意上传的能力。关于ASP.NET 下的上传组件最广为流传的方式莫过于在ASP.NET Pipeline 的BeginRequest 事件中截获当前的HttpWorkerRequest 对象然后直接调用其ReadEntityBody 等方法获取客户端传递过来的数据流并加以分析和处理。在ASP.NET 1.1 时期这么做的目的是为了直接将数据写入硬盘以避免上传内容消耗太多服务器内存但是现在自然已经不会因为这个原因而这么做了。从客户端发起请求到一定规模的数据传输完毕需要一段时间那么从HttpWorkerRequest 对象中读取数据流自然需要一段时间而在这段时间内客户端可以使用新的请求进行轮询来获得当前上传的状况。这就是获得上传进度的最传统的做法。这个做法的原理很容易理解但是写出一个完整的组件其实很不容易尤其是各种细节方面的问题会让人感到防不胜防。此类组件中最成功且最著名的莫过于NeatUpload 了。NeatUpload 是一个开源组件使用LGPL Lesser General Public License 许可协议也就是说它是“business-friendly” 的。NeatUpload 可以在ASP.NET 和mono 中使用能够将上传的文件存在硬盘中或者Sql Server 数据库中。NeatUpload 提供了两个服务器控件 和 。前者用于代替 可以通过它访问到用户通过特定上传框上传的内容后者则是一个进度条显示控件负责使用弹出窗口或内联的形式显示上传的进度。弹出窗口自不必说而所谓的“ 内联” 方式其实只是在页面中嵌入一个Iframe 元素然后通过不断刷新iframe 中的页面来进行进度展示而已—— 可见它和弹出窗口显示方式的区别仅仅在页面所处的位置。当然如果我们希望将其移植为AJAX 形式也不难只需开发一个页面继承NeatUpload 提供的ProgressPage 类并通过ProgressPage 所提供的一些属性总字节数已上传字节数已花时间etc. 来获得当前上传的进度最后直接使用Response.Write 输出JSON 形式的数据即可。事实上原本在iframe 或新窗口中的页面也是继承了ProgressPage 类并且使用HTML 的方式进行呈现而已本质上并没有太大区别。不过个人认为其实NeatUpload 的实用价值不高这点稍后再述它最大的意义还在于提供了一个完整的优秀的示例。NeatUpload 设计精巧注释完整是个不可多得学习案例。如果能够将NeatUpload 的代码研究一遍那么相信在编程能力和ASP.NET 的理解上都会上一个新的台阶。此外在NeatUpload 站点上还能够发现NeatHtml 。NeatHtml 是一个开源的Web 组件用于显示不安全的内容主要是用户输入内容例如博客评论论坛帖子等等主要用于避免跨站脚本XSS Cross-Site Scripting 等安全问题。作为组件的作者Dean 还将NeatHtml 所用到的技术总结为一篇Whitepaper 感兴趣的朋友可以看一下这是一份不可多得的技术资料。顺便提一下个人认为目前很多开发人员的编程能力还不够似乎很多人都过早地把精力放在了“ 设计” 或者某个特定的技术上而忽略了最基础的“ 编程能力” 也就是将一段思路转化为代码实现的能力。我发现很多朋友在解决问题的时候似乎都能很快得到解决方案并且叙述出来但是真正要使用代码来表现出来时却显得困难重重。其实在工作中思路或解决方案可以通过讨论而获得但是真正转化为代码的时候只能靠自己了。而且编程能力其实和所谓的“ 工作经验” 无关我建议以“ 应届毕业生”“ 自居” 的朋友可以定心地锻炼一下自己的编程能力。与NeatUpload 类似的开源组件还有Memba Velodoc XP Edition 它是Velodoc文件管理系统 的核心。不过严格说来这不仅仅是一个上传组件而是一套文件管理的解决方案它包含一个兼容IIS 7 集成管道模式的ASP.NET Http Module 支持大文件上传使用有趣的是NeatUpload 申明IIS 7的一个 Bug 使它无法在IIS 7 集成管道模式中使用。一个支持断点续传的ASP.NET Http Handler 。一系列ASP.NET 服务器端控件提供了文件上传功能所需的UI 包括一个多文件上传控件一个ListView 控件和一个进度条控件。一个Web 应用程序可以替换FTP 的交换文件方式支持Email 发送链接。它也是上面所提到的组件的使用示例。一个Windows Service 用于定期清理旧文件。一个测试项目、一个部署项目、以及一个安装项目。文档。回到NeatUpload 组件。说实话我始终不喜欢这种进度获取方式因为我觉得通过一个额外的请求对服务器进行轮询无疑是一个累赘。事实上如果需要上传大文件并且获得上传进度目前最好的方式应该是使用RIA 方式。最典型的RIA 上传方式就是利用Flash 了。ActionScript 2.0 中已经存在FileReference 和FileReferenceList 组件以支持单文件和多文件的上传有了这两个组件上传的各种信息已经能够完全在客户端获得而上传进度也自然能够计算出来。FileReference 和FileReferenceList 组件非常容易使用就连像我这样对Flash 一窍不通的人也能在短时间内作出一个简单的上传功能。但是自从有了swfupload 世界就变得更美好了。严格说来通过FileReference 所得到的上传进度是“ 客户端发送数据的进度” 而像NeatUpload 的做法得到的是“ 服务器端接受数据的进度” 两者不可混为一谈。swfupload 也是个开源组件顾名思义是使用Flash 进行上传。不过对于swfupload 来说Flash 的作用主要是“ 控制” 而不是“ 展示” 这无疑给了开发人员更大的灵活性。swfupload 的实现方式自然是利用了FileReference 和FileReferenceList 组件所提供的功能通过Flash 与JavaScript 的交互能力使得开发文件上传功能变得非常优雅和容易。有了swfupload 开发人员可以使用JavaScript 来实现各种显示方式开发像Flicker 一样酷酷的上传界面也不再是非常困难的事情了。swfupload 是个客户端组件它对于服务器端来说完全透明也就是说服务器端只需要使用对待普通form 的方式来处理即可。例如在ASP.NET 中我们可以使用Generic Handler 来处理客户端的文件上传。如下fileCollection 变量即为客户端Post 至服务器端所有文件的集合我们可以使用name 或下标的方式来获得其中的HttpPostedFile 对象。publicclassUploadHandler:IHttpHandler{publicvoidProcessRequest(HttpContextcontext){HttpFileCollectionfileColllectioncontext.Request.Files;...}publicboolIsReusable{...}}既然Flash 提供了文件上传功能Silverlight 作为微软主推的RIA 技术也不会缺了这项功能。这篇文章 源自Silverlight 2.0 的Quick Starts 展示了如何使用Silverlight 2.0 开发文件上传的功能感兴趣的朋友可以一读。围绕着ASP.NET 中上传文件这个话题也讨论了不少了还有什么没有涉及到的吗个人认为其实至少还有一个非常重要问题是没有讨论过那就是在处理上传文件时占用ASP.NET 处理线程的问题。众所周知ASP.NET 处理请求时会用到线程池中的线程当线程池中的线程被用完之后没有被处理的请求只能排队了。因此增大ASP.NET 应用程序吞吐量的一个重要手段就是为一些耗时的操作使用异步处理方式事实上这一命题可以在大部分应用中成立。例如一个数据库查询操作需要3 秒钟如果不使用异步操作处理线程就会被阻塞直至查询完成。如果使用异步方式来执行数据库查询在这3 秒钟内线程就可以用户处理其他请求当异步操作结束之后ASP.NET 就会使用另一个线程来继续处理这个请求。上传大文件也是一个长时间占用处理线程的工作而且遗憾的是这无法使用异步操作来完成通过异步操作来释放处理线程需要操作系统的支持因此只有少量功能可以使用异步操作。如果一个文件上传需要3 分钟时间那么在这3 分钟内就会独占一个处理线程如果上传文件的连接一多就会大大影响应用程序的性能—— 就像遭受了某种方式的DOS 攻击一样。因此即使使用了像NeatUpload 和swfupload 这样的组件也无法解决上传连接过多造成可用线程减少的问题。要解决这个问题并不容易以下是两种思路欢迎大家就此问题进行讨论扩展IIS 使上传文件或处理文件的过程不经ASP.NET 处理以减少ASP.NET 应用程序线程的消耗。现在有了IIS 7 如果使用集成管道模式应该也可以使用托管代码进行扩展。使用额外的ASP.NET 应用程序处理文件上传以节省上传文件的线程对原ASP.NET 应用程序线程的消耗。就先说到这里吧。下载完整示例下载完整示例