转载 http://blog.sina.com.cn/s/blog_8f32dc250100wva8.html
HTTP 文件上传的基本原理:
使用html 的<input type=”file” name=”xxx”> 标签,提交form 的几个属性必须为: method=post encType=multipart/form-data;
method 属性必须设为post的原因是:值不是放在URL之后传递到服务器的;
encType属性:这个属性管理的是表单的MIME编码
几个属性详解:
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data 不对字符编码,在使用包含文件上传控件的表单时,必须使用该值;对于“multipart/form-data”类型的form表单,浏览器上传的实体内 容中的每个表单字段元素的数据之间用字段分隔界线进行分割,两个分隔界线间的内容称为一个分区,每个分区中的内容可以被看作两部分,一部分是对表单字段元 素进行描述的描述头,另外一部是表单字段元素的主体内容
text/plain 空格转换为“+”,不对特殊字符编码
服务器端:
WEB服务器端程序接收到“multipart/form-data”类型的HTTP请求消息后,其核心和基本的编程工作就是读取请求消息中的实体内容,然后解析出每个分区的数据,接着再从每个分区中解析出描述头和主体内容部分。
要在jsp里获得上传的文件,就是通过request.getInputStream()来得到上传的整个post实体的流,用 request.getHeader("Content-Type")来取得实体内容的分界字符串,然后根据http协议,分析取得的上传的实体流,把文 件部分给筛出来,然后在服务器端保存到磁盘文件中,另外因为上传文件时,form的属性enctype="multipart/form-data",所 以其他表单参数在上传文件时也无法得到,除了筛出文件进行保存,还应该把其他的参数一起取出保存,以便在jsp程序中调用。
具体方法如下:
1、 根据request获得文件输入流;
2、 依次读取行,此时进行两部分内容的处理,
a:获取文件名
以 filename=”xxxxx”来标识一个文件头,
b:获取其他表单值(因为其流是按照multipart/form-data方式来编码的,所以在服务器端,不能直接用request.getParameter()来获得);
以name=”xxxx”来标识一个表单头
都以流头的字符标识为值的结束;
实体内容内部的字段分隔界线是在content-type头中指定的字段分隔界线前面增加了两个减号(-)字符而形成的(由浏览器随机生成,由浏览器 保证不会与用户上传的文件内容重复)
当找到一个分区的开始位置后,程序还需要分辨出分区中的描述头和主体内容,并对这两部分内容分开存储。如何分辨出一个分区的描述头和主体部分呢?每 个分区中的描述头和主体内容之间有一空行,再加上描述头后面的换行,这就说明描述头和主体部分之间是使用“\n”、“\r”、“\n”、“\r”这四个连 续的字节内容进行分隔。因此,程序需要把“\n”、“\r”、“\n”、“\r”这四个连续的字节内容作为描述头和主体部分之间的分隔界线,并在字节数组 缓冲区buffer中寻找这个特殊的分隔界线来识别描述头和主体部分。
3、 根据读到的文件信息(文件名,文件大小等),判断是否合法(文件类型、文件大小判断)。如果合适则返回,如果不合适则创建同名文件并将其删除;
演示Form 显示提交的流的格式: UI
当前的主流文件上传组件性能对比
1、smartUpload 2、FileUpload 3、Cos
实例演示性能对比:
jspSmartUpload
fileUpLoad
cos
20M 、75M 、300M
所以选择Cos作为内部读取解析文件流的组件;
使用组件而不是自己来解析文件流的原因:
1、 读取文件大小的限制,如同smartUpload 组件一样,上传的文件大小会受到JVM内存容量的限制,因为读取的文件流都是存储在内存之中的,而fileUpLoad和cos采用的是当文件读取到了一定的大小就先写到硬盘上的临时目录中;
2、 读取效率的限制 ,组件可以根据文件的大小设定一定的缓存,来提升读取的效率,分配好内存的缓存大小,及硬盘目录缓存大小;
(文件缓存循环机制作的简要介绍,缓冲区如何正好读取到分区界限)
此类组件的使用及封装方式:
MultipartRequest mu = new MultipartRequest(HttpServletRequest request,Directory,MaxSize,”gbk”);
我们只需要传递一个申请的request流,目录名,它会自动完成相应的解析文件流的过程,然后直接在对应设置的目录中生成对应的同名文件;
代理模式:
HttpServerRequestProxy:代理表单请求
InputStreamRequestProxy:代理输入流
整个的代理流程如下:
首先类HttpServerRequestProxy 继承于HttpServletRequestWrapper,并覆写它父类的getInputStream() 方法,在这个方法中我们设置它返回InputStreamRequestProxy流对象(当然这个类必须要与ServletInputstream 兼容,所以它必定继承于ServletInputstream),然后我们覆写这个流的read()方法,并在这个方法内部我们对文件上传的进度,速度进 行控制,而不是由组件提供的特定的进度监视器来获取准确的精度;
运行流程如下:
组件以HttpServerRequestProxy对象为参数进行初始化,在其内部再调用参数的getInputStream()方法获取整个传入流,再使用流的read()方法读取实际内容,这样整个处理流的过程,都是从代理中通过的;
服务器端获取文件传输速度的计算方式:
1. 根据前后读取buffer的时间来测算,但是由于读取request 返回的流太过频繁,导致以毫秒计算,根本没有办法来计算实时速度;(不可行)
2. 采用一个控制量,固定读取一定数量的buffer后,再根据服务器读取这段的长度所使用的时间来设定速度值;(需要设定BufferNUM的值,实时性较好,资源消耗最少);
3. 采用定时器,每过N秒访问一次文件读取的进度,设置相关的信息,但返回的上传速度可能为 0,或者是无穷;
判断上传文件(单个)大小是否符合服务器设置:
(如何快速判断,而不是等二进制流读取完再返回错误信息。)
javaScript 客户端脚本判断,但是针对不同的浏览器,不同的权限设置,不一定能成功;(且于服务器端实际读取的文件大小精度有差异,难以靠以上传的流的大小来保证文件是否已经上传完毕)
function ShowFileSize()
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f, s, file;
if ("object" != typeof(fso))
return;
file = FormName.fileName.value;
f = fso.GetFile(file);
alert(f.size);
}
服务器即时判断:服务器读取流,直到读取的流的数量大于所设定大的限制,则返回错误信息。(占太多的时间,且浪费服务器资源)
服务器端判断:在发送POST请求时,信息头里面都包含 Content-Length 属性,其代表着整个请求的数据长度。我们可以通过简单的判断这个Header数据,发现超过了我们允许的长度则直接断开连接,这样就不会对服务器造成资源浪费。
演示:simpleFileUpload index.jsp
如何判断批量上传的每一个文件的大小:
(使用方法二)
1. 在客户端判断文件大小,只提交服务器一个文件流,但是文件大小的精确程度会有一定程度的不同,导致一种假死现象;还会有客户端js代码的权限问题。
2. 在服务器端判断文件大小,但是服务器在真实读取文件流之前 ,使用上面的方法二,只能得到整个流的大小,不能得到,单个文件的大小;这样只能实现整个上传进度的统计。而不可能实现多个文件分开计算其精度的方法;
演示:simpleFileUpload pLOneStream.jsp
3.每个文件提交一个文件流,服务器对每个流处理时返回文件大小及文件进度。方法是,每个 <input type=”file”> 标签都置于一个独立的form表单中,然后一次提交;
服务器如何在真正文件上传(读取流)之前获得文件名?
按照正常的Http上传文件的方式是不能实现的,只有在客户端向服务器提交表单之前先向服务器提交一个Ajax请求,然后服务器调用Ajax请求传递过来 的参数(文件名)来判断是否符合服务器提交要求,如果符合则在客户端的回调函数中提交本文件所属的form表单;如果不符合则返回出错信息;
如果文件不合法,服务器、客户端如何而实现:
(此时服务器已经必定在读http传递过来的文件流,除非判断文件名是在客户端判断,或者是使用Ajax在服务器端判断的方法)
1、 客户端使用Ajax 接受服务器返回出错信息,并在服务器内部读取流文件时,如果发现文件不合法则抛出特定的异常,并在服务器内部自行捕获处理;
2、 流覆盖;
流覆盖演示:streamCover
原理:将两个请求同时提交到一个地方,导致后面的流截断前面正在上传的文件流,从而达到删除正在上传的文件的效果;(删除正在上传的文件)
客户端从服务器读取文件上传进度信息:
(Ajax)
几个重要的步骤:
1、 构建Ajax 对象;(需要针对不同的浏览器进行构建),参见代码;cosex---UpLoadFile.html—getAjax;
2、 设置回调函数 onreadystatechange;
3、 设置携带特定参数信息的URL;
4、 发送请求;
5、 等待回调;
需要注意的问题:
1、 IE缓存问题;
解决方法:
清除由于IE缓存造成的Ajax不能多次发出请求:
服务器端:
response.setHeader(“Cache-Control”,”no-cache”);
客户端
在Ajax发出的请求URL后添加一个随机数(Math.random()),这样对于IE来说每次请求的页面都不是同一个页面就不会造成直接调用缓存页面的问题;
2、 同步还是异步请求的问题;
Ajax的优势就是可以异步发送请求到服务器,而不需要服务器实时的去相应,所以设为异步;
服务器端相应Ajax请求的几个问题:
1、 Ajax异步请求与传统请求在服务器端的判断方法;
request.getHeader("x-requested-with");
b.在URL后添加一个与服务器端约定好的参数;
(在服务器端都必须显示的去判断)
2、 字符编码问题;
Ajax请求默认的参数默认均为 ”ISO8859-1”,在服务器端必须要进行解码;
与进度条的集成:
根据Ajax从服务器获取的文件信息(文件大小,上传速度,上传百分比等信息),信息每更新一次就设定进度条的值;动态隐藏和显示显示进度条的div;
UI上传组件应该具备以下基本功能:
1. 能让用户提供一个上传路径
2. 能够限制上载文件的大小(防止上传文件过大)
3. 能够支持多个文件同时上传及限制并行上传文件的个数(多文件并行上传)
4. 可以在服务器端进行异常错误捕获,并进行适当的处理
5. 上传组件的稳定性(上传速度能够保持稳定)
6. 可以设定屏蔽(或指定)固定类型的文件(如以 .exe结尾的文件等)
7. 能够向用户提供一个友好的交互界面,实时显示该文件上传的进度、当前用户的网络状态、上传此文件已花费时间、传输速率,剩余时间等信息
8. 支持对已上传或正在上传文件的删除
9. 用户使用及操作及可扩展 ,并能够灵活的集成到其它项目中
Ajax的同步问题 ;(两个不同的页面同时访问一个服务端URL,导致两者得到的值竟然是后者的值)
一个页面的,多表单提交的问题解决方案:
1. 使用Ajax 实现。
2. 使用 form 的target 属性提交到一个本页面的iframe 的name 上,那样页面就不会跳转。
Javascript问题:
引号中传字符串值; 可以单双引号嵌套使用
Setinterval()函数传值,采用
function(){ realFunction(args)} 的匿名传值方法;
3. 取消计时器clearInterval(timerID);
一个页面多次提交导致流被截断;
如果是提交到一个隐藏的frame中的话,那么会导致流被截断,必须提交到不同的隐藏frame中,才可以异步提交到服务器。
分享到:
相关推荐
Java 文件上传进度条实现的基本原理主要涉及到客户端与服务器之间的数据传输、多线程处理和用户界面更新。在本文中,我们将深入探讨这个过程,并提供一个简单的实现思路。 首先,了解文件上传的基本流程:用户选择...
本文将详细介绍Web文件上传的基本原理及其实现方法,并通过具体的代码示例来帮助读者更好地理解和掌握这一技术。 #### 二、HTTP表单上传规范 文件上传的核心是通过HTTP协议完成数据传输。当用户选择文件并提交表单...
下面我们将深入探讨文件上传的原理,包括其基本流程、技术实现、以及相关的安全措施。 #### 一、文件上传的基本流程 1. **用户选择文件**:在前端界面,用户通过点击“选择文件”按钮来挑选本地计算机上的文件。这...
在本文中,我们将深入探讨如何使用Servlet来理解Struts2中的文件上传原理。Servlet是Java Web应用程序中的一个组件,用于处理HTTP请求和响应。而Struts2是一个基于MVC(模型-视图-控制器)设计模式的开源Web应用框架...
通过以上介绍,我们可以看到文件上传的基本原理并不复杂,但它涉及到客户端与服务器之间的通信细节,以及如何正确解析和处理HTTP请求体中的多部分格式数据。掌握这些原理有助于开发者更好地理解和解决在实际项目中...
计算机病毒与防护:文件上传漏洞原理 文件上传漏洞是网络安全领域中的一个重要问题,尤其是在Web应用程序中,这种漏洞可能导致严重的安全威胁。许多网站提供文件上传功能,例如用户上传头像、社交网络上的照片分享...
首先,我们需要了解HTTP上传文件的基本原理。通常,文件上传是通过POST请求实现的,其中包含一个名为"multipart/form-data"的Content-Type,用于分隔不同的数据部分。每个部分都有自己的边界,以便服务器能够正确...
首先,我们需要理解HTTP协议的基本原理。HTTP(超文本传输协议)是互联网上应用最为广泛的一种网络协议,主要用于从Web服务器传输超文本到本地浏览器。HTTP Upload则是指通过HTTP协议将文件数据发送到服务器的过程,...
PHP作为当前流行的Web应用程序开发技术,对于一个完整的Web应用程序,文件上传是其基本功能之一。下面将详细论述PHP开发环境下文件上传的原理与实现方法,并对上传文件的格式类型及大小进行限制。 一、PHP简介 ...
HTTP(超文本传输协议)是互联网上...总的来说,HTTP文件上传与下载是Web应用中常见的功能,理解其原理和实现方式对于开发人员来说至关重要。通过实际代码示例学习,可以更深入地掌握这一过程,并能应用于实际项目中。
以下是一个基本的文件上传示例,使用`HttpClient`: ```csharp using System.IO; using System.Net.Http; using System.Threading.Tasks; public async Task UploadFile(string url, string filePath) { var ...
1. **文件上传原理**: 文件上传是通过HTTP协议的POST请求来完成的,通常使用`multipart/form-data`编码类型。在客户端,HTML表单中的`<input type="file">`元素允许用户选择本地文件;在服务器端,我们需要解析...
**HTTP 文件上传的基本原理** 1. **POST 请求**:文件上传通常通过HTTP的POST方法完成。客户端(通常是Web浏览器)构造一个包含文件数据的HTTP请求,目标URL指向服务器上的接收文件的端点。 2. **Multipart/form-...
在这个项目中,我们关注的是通过HTTP协议进行数据交换,特别是涉及多文件上传。以下是对这个项目及其相关知识点的详细说明: 首先,`CHttpFile` 是Microsoft的MFC(Microsoft Foundation Classes)库中的一个类,它...
Spring Multipart工作原理详解——文件上传到服务器 在Web应用中,文件上传功能是常见的需求之一,Spring框架提供了对文件上传的支持,主要基于MultipartFile接口。本文将深入探讨Spring Multipart的工作原理,以及...
首先,了解HTTP文件上传的基本原理。在HTTP中,文件上传通常使用POST方法,通过表单数据或者Multipart/form-data编码来发送。这种编码方式允许我们同时发送文本数据和二进制文件,是HTTP文件上传的标准。 在Java中...
下面我们将详细探讨文件上传的基本原理、File控件的作用以及如何利用jar包来实现文件上载。 1. **文件上传基本原理** 文件上传的过程涉及到客户端(浏览器)与服务器之间的交互。当用户在表单中选择文件并提交时,...
在IT行业中,C#是一种广泛使用的编程语言,尤其在开发Web应用程序时,如WebAPI。...通过研究这些源码,开发者可以深入理解WebAPI的工作原理,以及如何在实际项目中安全、高效地处理文件上传和下载。
首先,我们要理解HTTP的基本原理。HTTP是一个无状态、基于请求-响应模型的协议,用于在Web上交换数据。它通过TCP/IP连接进行通信,用户代理(如浏览器)向服务器发送请求,服务器接收请求后返回响应。在C语言中,...