首页 > 代码库 > 上传文件

上传文件

上传文件

1、Form表单上传

接下来我们使用HTML标签来创建文件上传表单,以下为要注意的点:

  • form表单 method 属性必须设置为 POST 方法 ,不能使用 GET 方法。
  • form表单 enctype 属性需要设置为 multipart/form-data

  enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。而当设置了该编码格式时,不能直接上传文件。因此,这里我们使用另外一种编码格式,即multipart/form-data,该编码格式不对数据进行编码,而是直接上传二进制数据,form里面的input的值以二进制的方式传过去。

技术分享
<!DOCTYPE html><html><head>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>    <title>上传文件</title></head><body>    <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >        <input name="fff" id="my_file"  type="file" />        <input type="submit" value=http://www.mamicode.com/"提交"  />    </form></body></html>
index.html
技术分享Python

注意:这种传统的表单上传,属于"同步上传"。也就是说,点击上传按钮后,网页"锁死",用户只能等待上传结束,然后浏览器刷新,跳到表单的action属性指定的网址。

2、AJAX上传

  对于传统的表单上传,如果我们上传的是一份大文件的话,那你就在那里干等着吧。如此low的用户体验肯定不是我们想要的。那我们该怎么办呢?这时候我们就要用到Ajax“异步上传”了

技术分享
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <input type="file" id="img" />    <input type="button" onclick="UploadFile();" />    <script>//创建一个表单对象        function UploadFile(){            var fileObj = document.getElementById("img").files[0];//主要用的是FormData对象,它能够构建类似表单的键值对。FormData可以凭空创建一个对象,然后往这个对象里面添加数据,然后直接提交            var form = new FormData();            form.append("k1", "v1");            form.append("fff", fileObj);            var xhr = new XMLHttpRequest();            xhr.open("post", /index, true);            xhr.send(form);        }    </script></body></html>
HTML - XMLHttpRequest
技术分享
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <input type="file" id="img" />    <input type="button" onclick="UploadFile();" />    <script>        function UploadFile(){            var fileObj = $("#img")[0].files[0];            var form = new FormData();            form.append("k1", "v1");            form.append("fff", fileObj);            $.ajax({                type:POST,                url: /index,                data: form,                cache: false                processData: false,  // tell jQuery not to process the data                contentType: false,  // tell jQuery not to set contentType                success: function(arg){                    console.log(arg);                }            })        } /*cache    cache设为false可以禁止浏览器对该URL(以及对应的HTTP方法)的缓存。 jQuery通过为URL添加一个冗余参数来实现。    该方法只对GET和HEAD起作用,然而IE8会缓存之前的GET结果来响应POST请求。 这里设置cache: false是为了兼容IE8。contentType    jQuery中content-type默认值为application/x-www-form-urlencoded, 因此传给data参数的对象会默认被转换为query string(见HTTP 表单编码 enctype)。    我们不需要jQuery做这个转换,否则会破坏掉multipart/form-data的编码格式。 因此设置contentType: false来禁止jQuery的转换操作。processData    jQuery会将data对象转换为字符串来发送HTTP请求,默认情况下会用 application/x-www-form-urlencoded编码来进行转换。 我们设置contentType: false后该转换会失败,因此设置processData: false来禁止该转换过程。    我们给的data就是已经用FormData编码好的数据,不需要jQuery进行字符串转换。    */    </script></body></html>     
HTML - jQuery

  jQuery文件上传方式依赖于FormData对象, 这是XMLHttpRequest Level 2接口, 需要 IE 10+, Firefox 4.0+, Chrome 7+, Safari 5+, Opera 12+

这意味着对于低版本浏览器只能使用直接提交文件表单的形式, 但提交大文件表单页面会长时间不响应,如果希望在低版本浏览器中解决该问题, 就只能使用别的方式来实现了,比如很多支持多文件和上传进度的Flash插件。

iframe上传

在HTML5没有出现之前,只能用iframe来实现“异步上传”。用户点击submit时,动态插入一个iframe元素

技术分享
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >        <div id="main">            <input name="fff" id="my_file"  type="file" />            <input type="button" name="action" value=http://www.mamicode.com/"Upload" onclick="redirect()"/>            <iframe id=my_iframe name=my_iframe src=http://www.mamicode.com/""  class="hide"></iframe>        </div>    </form>    <script>        function redirect(){            document.getElementById(my_iframe).onload = Testt;  //iframe加载完成后立马执行            document.getElementById(my_form).target = my_iframe; //,它为表单添加target属性,指向动态插入的iframe窗口,这使得上传结束后,服务器将结果返回iframe窗口,所以当前页面就不会跳转了            document.getElementById(my_form).submit();        }                function Testt(ths){            var t = $("#my_iframe").contents().find("body").text();            console.log(t);        }    </script></body></html>
HTML - iframe
技术分享
#!/usr/bin/env python# -*- coding:utf-8 -*-import tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        self.render(index.html)    def post(self, *args, **kwargs):        file_metas = self.request.files["fff"]        # print(file_metas)        for meta in file_metas:            file_name = meta[filename]            with open(file_name,wb) as up:                up.write(meta[body])settings = {    template_path: template,}application = tornado.web.Application([    (r"/index", MainHandler),], **settings)if __name__ == "__main__":    application.listen(8000)    tornado.ioloop.IOLoop.instance().start()
Python
技术分享
<script type="text/javascript">     $(document).ready(function () {         $("#formsubmit").click(function () {             var iframe = $(<iframe name="postiframe" id="postiframe" style="display: none"></iframe>);             $("body").append(iframe);             var form = $(#theuploadform);            form.attr("action", "/upload.aspx");            form.attr("method", "post");             form.attr("encoding", "multipart/form-data");            form.attr("enctype", "multipart/form-data");             form.attr("target", "postiframe");            form.attr("file", $(#userfile).val());            form.submit();             $("#postiframe").load(function () {                iframeContents = this.contentWindow.document.body.innerHTML;                $("#textarea").html(iframeContents);            });             return false;         });     }); </script>  <form id="theuploadform">    <input id="userfile" name="userfile" size="50" type="file" />    <input id="formsubmit" type="submit" value=http://www.mamicode.com/"Send File" /></form> <div id="textarea"></div>
扩展:基于iframe实现Ajax上传示例
技术分享
$(#upload_iframe).load(function(){                    var iframeContents = this.contentWindow.document.body.innerText;                    iframeContents = JSON.parse(iframeContents);                                   })
View Code
技术分享
function bindChangeAvatar1() {            $(#avatarImg).change(function () {                var file_obj = $(this)[0].files[0];                $(#prevViewImg)[0].src =http://www.mamicode.com/ window.URL.createObjectURL(file_obj)            })        }        function bindChangeAvatar2() {            $(#avatarImg).change(function () {                var file_obj = $(this)[0].files[0];                var reader = new FileReader();                reader.readAsDataURL(file_obj);                reader.onload = function (e) {                    $(#previewImg)[0].src =http://www.mamicode.com/ this.result;                };            })        }        function bindChangeAvatar3() {            $(#avatarImg).change(function () {                var file_obj = $(this)[0].files[0];                var form = new FormData();                form.add(img_upload, file_obj);                $.ajax({                    url: ‘‘,                    data: form,                    processData: false,  // tell jQuery not to process the data                    contentType: false,  // tell jQuery not to set contentType                    success: function (arg) {                    }                })            })        }        function bindChangeAvatar4() {            $(#avatarImg).change(function () {                $(this).parent().submit();                $(#upload_iframe).load(function () {                    var iframeContents = this.contentWindow.document.body.innerText;                    iframeContents = JSON.parse(iframeContents);                    if (iframeContents.status) {                        $(#previewImg).attr(src, / + iframeContents.data);                    }                })            })        }
其他

3、进度条

XMLHttpRequest第二版还定义了一个progress事件,可以用来制作进度条。

首先,在页面中放置一个HTML元素progress。

 <progress id="uploadprogress" min="0" max="100" value=http://www.mamicode.com/"0">0</progress>

然后,定义progress事件的回调函数。

技术分享
xhr.upload.onprogress = function (event) {    if (event.lengthComputable) {      var complete = (event.loaded / event.total * 100 | 0);      var progress = document.getElementById(‘uploadprogress‘);      progress.value = progress.innerHTML = complete;    }  };
View Code

注意,progress事件不是定义在xhr,而是定义在xhr.upload,因为这里需要区分下载和上传,下载也有一个progress事件。

4、图片预览

如果上传的是图片文件,利用File API,我们可以做一个图片文件的预览。这里主要用到FileReader对象。

技术分享
 // 检查是否支持FileReader对象  if (typeof FileReader != undefined) {    var acceptedTypes = {      image/png: true,      image/jpeg: true,      image/gif: true    };    if (acceptedTypes[document.getElementById(upload).files[0].type] === true) {      var reader = new FileReader();      reader.onload = function (event) {        var image = new Image();        image.src = event.target.result;        image.width = 100;        document.body.appendChild(image);      };    reader.readAsDataURL(document.getElementById(upload).files[0]);    }  }
View Code

5、拖放上传

最后,利用HTML5的拖放功能,实现拖放上传。

先在页面中放置一个容器,用来接收拖放的文件。

 <div id="holder"></div>

对它设置样式:

技术分享
 #holder {    border: 10px dashed #ccc;    width: 300px;    min-height: 300px;    margin: 20px auto;  }  #holder.hover {    border: 10px dashed #0c0;  }
View Code

拖放文件的代码,主要是定义dragover、dragend和drop这三个事件。

技术分享
 // 检查浏览器是否支持拖放上传。  if(‘draggable‘ in document.createElement(‘span‘)){    var holder = document.getElementById(‘holder‘);    holder.ondragover = function () { this.className = ‘hover‘; return false; };    holder.ondragend = function () { this.className = ‘‘; return false; };    holder.ondrop = function (event) {      event.preventDefault();      this.className = ‘‘;      var files = event.dataTransfer.files;      // do something with files    };  }
View Code

 

参考:http://www.ruanyifeng.com/blog/2012/08/file_upload.html

参考:http://www.cnblogs.com/wupeiqi/articles/5702910.html

上传文件