关于文件上传功能的思考

概述

文件上传是一个很常见的需求,实现文件上传的技术也很多。下面就谈谈一些常见的上传技术以及它们的优劣。

传统表单上传

传统表单文件上传估计是运用最广泛和最简单的技术了,说它简单是因为只要指定表单的enctype为multipart/form-data,就行了。简单可靠所以被运用的广泛。传统表单上传示例如下所示:

<form action="test.php" target="" method="post" enctype="multipart/form-data">
    <input type="file" name="file" id="file" />
    <input type="submit" id="J_submit"  value="submit" />
</form>

表单中的action参数指的是后台处理上传文件的接口。target参数规定了规定在何处打开 action URL,常见的参数有_blank、_self、__top或者指定的iframe。method参数规定了表单提交的方式,这里只能使用**post**方式提交,而不能用**get**方式。最后enctype的参数规定了在发送到服务器之前应该如何对表单数据进行编码方式,常见的参数有**application/x-www-form-urlencoded**、**text/plain**和示例中的**multipart/form-data**,因为上传的文件都是非纯文本传输,所以指定的类型必须只能是**multipart/form-data**。

这种方式的局限性是不能批量处理,而且表单上传是同步的,表单已提交,页面就会刷新。

第三方插件处理文件上传

如果你想实现异步提交文件,且可以进行批量处理文件,那么只能通过第三方插件来实现了,第三方插件实现技术有很多,比如Flash、java applet、ActiveX等技术,其中Flash技术是运用最广泛、最成熟的一种方案。

不过第三方插件已经不属于前端开发范围了,所以不会详细细说。不过到时可以我常用的FLash上传插件有SWFupload、uploadfile、百度的webupload等。

第三方插件的好处是能做批量处理、异步提交。缺点也是显而易见的是要浏览器支持。

模拟异步上传文件

说到异步,可能有人会说,能不能通过ajax来实现文件的异步上传呢?想法很美好,现实却很残酷,ajax与后端通信 只能传送字符串,是无法传递实体文件的,所以用ajax是无法实现直接文件上传的。不过我们却可以在页面“埋”一个隐藏iframe来模拟文本的异步提交。

具体的原理是,在点击提交按钮时,动态的生成一个隐藏iframe加入到页面上,并且 将form 的 target指向该隐藏iframe,服务端就接收到上传的file文件,并进行相应的操作,然后将返回结果返回到隐藏的iframe里面,这时我们可以与后端开发约定返回结果的格式,可以是json格式,便于我们前端操作,然后前端部分就可以用iframe.contentWindow.document.body.innerHTML来获取后端返回的结果,进行相应的parseJSON处理,即可像处理ajax返回的json一样,处理数据。

示例代码如下所示:

/**
 * 模拟ajax无刷新文件上传
 */
var fileUpLoad = function(config) {

    var ifr = null,
        fm = null,
        defConfig = {
            submitBtn: $(‘#J_submit‘), //提交按钮
            complete: function(response) {}, //上传成功后回调
            beforeUpLoad: function() {}, //点击提交未上传时回调
            afterUpLoad: function() {} //点击提交上传后回调
        };

    //静态变量
    var IFRAME_NAME = ‘fileUpLoadIframe‘;

    //配置
    config = $.extend(defConfig, config);

    //绑定submit事件
    config.submitBtn.bind(‘click‘, function(e){
        e.preventDefault();

        //点击提交前触发事件, 函数返回false可阻止提交表单,用于file为空判断
        if (config.beforeUpLoad.call(this) === false) {
            return;
        }

        //生成一个隐藏iframe,并设置form的target为该iframe,模拟ajax效果
        ifr = $(‘<iframe name="‘+ IFRAME_NAME +‘" id="‘+ IFRAME_NAME +‘" style="display:none;"></iframe>‘);
        fm = this.form;

        ifr.appendTo($(‘body‘));
        fm.target = IFRAME_NAME; //target目标设为ifr

        //上传完毕iframe onload事件
        ifr.load(function(){
            var response = this.contentWindow.document.body.innerHTML;

            config.complete.call(this, response);
            ifr.remove();
            ifr = null; //清除引用
        });

        fm.submit(); //提交表单

        //点击提交后触发事件
        config.afterUpLoad.call(this);

    });

};

调用方式如下:

fileUpLoad({
    submitBtn: $(‘#J_submit‘),
    complete: function(response){ //上传成功后处理回调
        var d = $.parseJSON(response);

        alert(‘返回成功‘)
        console.log(d);
    },
    beforeUpLoad: function() {
        alert(‘上传前‘);
    },
    afterUpLoad: function() {
        alert(‘上传后‘);
    }
}); 

这种方式的好处是,虽然不是异步提交,但是给人的感觉好像是通过异步方式上传了文件。缺点是依然不能进行批量处理文件。

使用FormData对象发送文件

XMLHttpRequest Level 2添加了一个新的接口FormData.利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单".比起普通的ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件.其兼容性如下所示:

有图可知,这个接口兼容性在IE上表现的并不是很好,最新只支持IE10+,不过IE10+的市场份额现在还不是很多,如果你考虑兼容性的话,建议不要使用这个接口。

那怎样通过FormData上传文件呢。可以参考下面的代码。
html结构:

<form enctype="multipart/form-data" method="post" name="fileinfo">
  <label>Your email address:</label>
  <input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br />
  <label>Custom file label:</label>
  <input type="text" name="filelabel" size="12" maxlength="32" /><br />
  <label>File to stash:</label>
  <input type="file" name="file" required />
</form>
<div id="output"></div>
<a href="javascript:sendForm()">Stash the file!</a>   

脚本代码:

function sendForm() {
  var oOutput = document.getElementById("output");
  var oData = new FormData(document.forms.namedItem("fileinfo"));

  oData.append("CustomField", "This is some extra data");

  var oReq = new XMLHttpRequest();
  oReq.open("POST", "stash.php", true);
  oReq.onload = function(oEvent) {
    if (oReq.status == 200) {
      oOutput.innerHTML = "Uploaded!";
    } else {
      oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>";
    }
  };

  oReq.send(oData);
}    
时间: 2024-11-05 02:10:31

关于文件上传功能的思考的相关文章

文件/大文件上传功能实现(JS+PHP)全过程

文件/大文件上传功能实现(JS+PHP) 参考博文:掘金-橙红年代 前端大文件上传 路漫漫 其修远 PHP + JS 实现大文件分割上传 本文是学习文件上传后的学习总结文章,从无到有实现文件上传功能,前端小白写的代码不是最优,如果有错误的地方请多多指教,如果本文对你有所帮助,深感荣幸. 近期公司的项目中,涉及到上传大文件的问题,大文件上传用普通表单上传时出现的问题是,无法断点续存,一但中途中断上传,就要重头开始,这很明显不是我们想要的,所以经过一番查询,学习了一下大文件分割上传的方法.并且使用简

达到HTTP合约Get、Post和文件上传功能——采用WinHttp介面

于<采用WinHttp实现HTTP协议Get.Post和文件上传功能>一文中,我已经比較具体地解说了怎样使用WinHttp接口实现各种协议. 在近期的代码梳理中,我认为Post和文件上传模块能够得到简化,于是差点儿重写了这两个功能的代码.由于Get.Post和文件上传功能的基础(父)类基本没有修改,函数调用的流程也基本没有变化,所以本文我将重点解说修改点. (转载请指明出于breaksoftware的csdn博客) 首先我改动了接口的字符集.之前我都是使用UNICODE作为接口參数类型,当中一

实现HTTP协议Get、Post和文件上传功能——使用libcurl接口实现

之前我们已经详细介绍了WinHttp接口如何实现Http的相关功能.本文我将主要讲解如何使用libcurl库去实现相关功能.(转载请指明出于breaksoftware的csdn博客) libcurl在http://curl.haxx.se/libcurl/有详细的介绍,有兴趣的朋友可以去读下.本文我只是从实际使用的角度讲解其中的一些功能. libcurl中主要有两个接口类型:CURL和CURLM.CURL又称easy interface,它接口简单.使用方便,但是它是一个同步接口,我们不能使用它

实现HTTP协议Get、Post和文件上传功能——使用WinHttp接口实现

在<使用WinHttp接口实现HTTP协议Get.Post和文件上传功能>一文中,我已经比较详细地讲解了如何使用WinHttp接口实现各种协议.在最近的代码梳理中,我觉得Post和文件上传模块可以得到简化,于是几乎重写了这两个功能的代码.因为Get.Post和文件上传功能的基础(父)类基本没有改动,函数调用的流程也基本没有变化,所以本文我将重点讲解修改点.(转载请指明出于breaksoftware的csdn博客) 首先我修改了接口的字符集.之前我都是使用UNICODE作为接口参数类型,其中一个

文件上传功能的实现

一:文件上传功能 先要在在index.jsp的界面上初始化一个表单. 代码如下: <body> <form enctype="multipart/form-data" action="<%=path%>/1.jsp" method="post"> 姓名:<input type="text" name="username"/> 选择文件:<input ty

AEAI Miscdp文件上传功能使用心得

1.概述 在实际项目中,我们常常可以遇到这样的情况:上传头像.上传图片.上传视频.上传音乐.上传作业,等等-那么如何使用MiscdpStudio对这类功能进行开发,就成了MiscdpStudio使用者必须掌握的技能之一. 接下来,我就对单表操作模型,简单介绍一下如何对文件进行上传.这里,我们主要使用的是fileupload组件,当然,这也是开发平台中自带的组件. 2.创建数据表 在这里,我们需要在数据库创建两个表,一个是业务表.另一个是关联表.关联表里有三个字段:逻辑主键.业务标识字段.附件标识

iOS 的 Safari 文件上传功能详解

iOS 6 给 Safari 浏览器带来的另外一个功能是文件上传,终于 Safari 终于支持 input 输入框的文件类型了,并且还支持 HTML媒体捕获(HTML Media Capture). 上传单张图片或者视频 <input type="file"> 可以选择直接拍照或者摄影,也可以从相册中选取.选好之后,iOS 上的 Safari 和其他浏览器不同是它显示图片的截图,而不是图片的临时名称. 上传多张图片或者视频 如果你想一次上传多张图片,可以使用 HTML5 一

Spring MVC 文件上传功能详解

前言 在Spring MVC中实现文件上传功能并不复杂,前端使用HTML语法,后端使用特定抽象.参考Spring Boot相关文档即可.本文主要讲解常见资料忽略的两个问题: 文件上传错误 链接重置问题 版本:Spring Boot 1.5x 文件上传错误 一个关注点是如何处理文件上传期间发生的错误,错误主要分为两类: IOException 文件读取或写入错误. MultipartException 上传文件时,超过文件大小上限所触发的异常. IOException 只需要在Controller

文件上传功能实现(一)

文件上传: ①上传前的准备工作(准备一个注册的表单页面) 创建一个文件上传的控件,点击这个控件就可以选择需要上传的文件了 <form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="headimg" /> 注意:上传时表单的上传类型必须是:multipart/