Web上传文件的原理及实现[转]

摘要:
现在,许多Web程序都有上传功能,也有许多组件或框架来实现上传功能,例如基于Java的CommonsFileUpload,以及Struts1.x和Struts2.asp.Net中的上传文件功能。尽管现在有很多上传组件可用,但了解在Web上上传文件的原理将非常有助于处理突发问题。让我们来谈谈通过浏览器上传文件的基本原理。以下是文件的具体内容。测试后,内容类型中的“-”分隔符比实际上传的“-“分隔符少两个。我不知道为什么。
   现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于javaCommons FileUpload、还有Struts1.xStruts2中带的上传文件功能(实际上,Struts2在底层也使用了Commons FileUpload)。在asp.net中也有相应的上传文件的控件。

虽然现在有很多上传组件可以利用,但是了解Web上传文件的原理,对于处理突然出现的问题会有很大的帮助,下面就来讲一下通过浏览器上传文件的基本原理。在了解了原理之后,就可以非常容易地自制满足自身需要的上传组件了。

众所周知,在客户端代码中需要使用<input type='file' name='file' />来选择要上传的文件,并上传,代码如上:

<html>
    
<head>
        
<title>upload</title>
        
<meta http-equiv="description" content="this is my page">
        
<meta http-equiv="content-type" content="text/html; charset=GB18030">
    
</head>

    
<body>
        
<form action="servlet/UploadFile" method="post"
            enctype
="multipart/form-data">
            
<input type="file" name="file1" id="file1" />
            
<input type="file" name="file2" id="file2" />
            
<input type="submit" value="上传" />
        
</form>
    
</body>
</html>

从上面的代码可以看出,有两个文件选择框(file1file2),在上传文件时,<form>标签必须加上enctype="multipart/form-data",否则浏览器无法将文件内容上传到服务端。下面我们来做个实验。在ServletdoPost方法中编写如下的代码,如果想使用asp.net或其他的语言或技术,也可以很容易实现相应的功能。

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, IOException
    {
        java.io.InputStream is 
= request.getInputStream();
        java.io.FileOutputStream fos 
= new java.io.FileOutputStream("d:\\out.txt");
        
        
byte[] buffer = new byte[8192];
        
int count = 0;
        
while((count = is.read(buffer)) >0)
        {
            fos.write(buffer, 
0, count);
        }        
        fos.close();
    }

    上面的功能非常简单,只是通过request获得一个InputStream对象,并通过这个对象从客户端获得发送过来的字节流(注意,一定要用字节流,因为,上传的文件可能是二进制文件,如图象文件,因此,使用字节流会更通用)。并将这些字节流保存在D盘的out.txt文件中。然后我们打开out.txt,文件的内容如图1所示:
                                                                                                  Web上传文件的原理及实现[转]第1张


                                                                                   图1

    由于out.txt是使用文本形式打开的,并且file1上传的是a.jpg(一个图象文件),因此,显示的是一些乱码。我们可以不用管它们。只需要看看这些内容的头部。我们很快就可以找到规律。每一个文件内容的头部都由“-----------------------------30514443229777”分隔,然后是这个文件的属性,如下:

Content-Disposition: form-data; name="file1"; filename="a.jpg"

Content-Type: image/jpeg

其中包含了文件选择框的name属性,还有上传的文件名(filename字段),要注意的,firefox在上传时,这个filename属性值只是文件名,如果使用IE,就是带路径的文件名,如D:"a.jpg

接下来的规则就和HTTP的头一样了,以一个空行("r"n)分隔。后面就是文件的具体内容。现在最关键的文件的结尾,从图1可以看出,文件的结尾也是“-----------------------------30514443229777”,因此,可以断定,第一个上传的文件(包括文件头)是夹在两个“-----------------------------30514443229777”之间的。而“-----------------------------30514443229777”就是multipart/form-data协议的分隔符。但这里还有一个最关键的问题。这个分隔符每次上传都不一样,服务端是如何知道每次上传的这个分隔符的呢?

实际上,这个分隔符是通过HTTP请求头的Content-Type字段获得,可通过下面的代码输出这个字段值:

System.out.println(request.getHeader("Content-type"));

输出的内容如下:

multipart/form-data; boundary=---------------------------106712230227687

只要在服务端获得boundary后面的值即可。经过测试,Content-Type中的分隔符号中的“-”比实际上传的“-”少两个,不知是怎么回事。不过这没关系,我们可以认为每一个文件块是以""r"n—“结尾的,或是直接将从boundary获得的分隔符加两个“”。而最后结尾的分隔符是“---------------------------106712230227687—”,后面多了两个“”。

综合上述,也就是说,一个文件块是以“---------------------------106712230227687”开头,以“”结尾,从图2可以看出这一切。

Web上传文件的原理及实现[转]第2张
                                   
                                         图
2

    至于剩下的工作,就是按着上面的规则来分析这些字符流了。分析的方法很多。在这里就不详述了。

multipart/form-data规 范原文:http://www.ietf.org/rfc/rfc2388.txt

Form-based File Upload in HTML:http://www.ietf.org/rfc/rfc1867.txt

免责声明:文章转载自《Web上传文件的原理及实现[转]》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇陶瓷基板WPF 常用控件属性下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java Web开发之详解JSP

JSP作为Java Web开发中比较重要的技术,一般当作视图(View)的技术所使用,即用来展现页面。Servlet由于其本身不适合作为表现层技术,所以一般被当作控制器(Controller)所使用,而JavaBean作为模型(Model)层使用。这就是经典的MVC模型。 Servlet和JSP的关系上篇博客已经讲过了,并演示了一个相当简单的例子。在具体讲...

linux全部替换命令学习

:%s/准备替换内容/新内容/g 可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符:%s#vivian/#sky/#g 替换 vivian/ 为 sky/:%s+/oradata/apras/+/user01/apras1+ g (使用+ 来 替换 / ): /oradata/apras/替换成/user01/apras1/...

Swing菜单与工具栏(三)

6.1.6 JSeparator类 JSeparator类是一种特殊的组件,他在JMenu上提供分隔符。JPopupMenu与JToolBar类也支持分隔,但是每一个都使用JSeparator类的相应子类。除了可以放置在菜单上以外,JSeparator类也可以放置在任何我们希望使用水平或是垂直线来分隔屏幕不同区域的地方。 JSeparator是一个严格的...

Tomcat 修改上传文件默认权限

编辑tomcat根目录/bin/catalina.sh文件,找到 # Set UMASK unless it has been overridden if [ -z "$UMASK" ]; then UMASK="0027" fi umask $UMASK 将0027改成0022,重启...

让Apache Shiro保护你的应用

https://www.ibm.com/developerworks/cn/web/wa-apacheshiro/index.html Apache Shiro 是一个框架,可用于身份验证和授权。本文提供了几个示例用来展示如何在 Java™ 应用程序中使用 Shiro 并给出了如何在一个 Grails web 应用程序中使用它的概述。为了从本文中最大限度地...

复习java web之jsp入门_El表达式_JSTL标签库

JSP 技术掌握:JSP语法 + EL + JSTL 为什么sun推出 JSP技术 ?Servlet 生成网页比较复杂,本身不支持HTML语法,html代码需要通过response输出流输出,JSP支持HTML语法,生成HTML方便。 JSP技术与Servlet 技术区别和关系?JSP和Servlet技术都是用来动态生成网页的,Servlet不支持HTML...