Code Monkey home page Code Monkey logo

webuploader's Introduction

不再对使用问题进行答复,如果有希望的功能改进或者bugfix可以提交PR

WebUploader 文件上传 Build Status Built with Grunt

WebUploader是一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,延用原来的FLASH运行时,兼容IE6+,Andorid 4+,IOS 6+。两套运行时,同样的调用方式,可供用户任意选用。

支持大文件分片并发上传,极大的提高了文件上传效率。

支持

代码肯定存在很多不足和需要优化的地方,欢迎大家提交 pr。感谢以下代码贡献者, 排名不分先后。

@zensh@ushelp@duanlixin

特性

分片、并发

分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上传速度。

当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。另外分片传输能够更加实时的跟踪上传进度。

预览、压缩

支持常用图片格式jpg,jpeg,gif,bmp,png预览与压缩,节省网络数据传输。

解析jpeg中的meta信息,对于各种orientation做了正确的处理,同时压缩后上传保留图片的所有原始meta数据。

多途径添加文件

支持文件多选,类型过滤,拖拽(文件&文件夹),图片粘贴功能。

粘贴功能主要体现在当有图片数据在剪切板中时(截屏工具如QQ(Ctrl + ALT + A), 网页中右击图片点击复制),Ctrl + V便可添加此图片文件。

HTML5 & FLASH

兼容主流浏览器,接口一致,实现了两套运行时支持,用户无需关心内部用了什么内核。

同时Flash部分没有做任何UI相关的工作,方便不关心flash的用户扩展和自定义业务需求。

MD5秒传

当文件体积大、量比较多时,支持上传前做文件md5值验证,一致则可直接跳过。

如果服务端与前端统一修改算法,取段md5,可大大提升验证性能,耗时在20ms左右。

易扩展、可拆分

采用可拆分机制, 将各个功能独立成了小组件,可自由搭配。

采用AMD规范组织代码,清晰明了,方便高级玩家扩展。

webuploader's People

Contributors

2betop avatar belinchung avatar ben1226q avatar colinniu avatar duanlixin avatar fforever14 avatar gilbertsun avatar gmuteam avatar jarvanxing avatar kkirsche avatar konanzheng avatar limodou avatar markxuxiao avatar miller avatar qingdengyue avatar seeguitar avatar sunln avatar terevor avatar tiye avatar ushelp avatar wengys avatar wpg avatar xspider avatar yeol avatar yumozhi avatar zensh avatar zhuweiyou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webuploader's Issues

建议增加单个上传周期开始事件

当前事件就是整体开始,整体结束, 没有单个文件上传周期的开始上传开始事件。如果需要对单个文件上传周期开始设置点什么东西的时候不是很方便。

初次加载,无法打开选择图片的窗口

当把上传的插件放在一个display=none的div标签中时,当这个div变成display时,依然无法打开,如果不放在display=none为none的标签中,则可以打开,请问是什么原因,JS的引入放在了div加载后了,已经
程序如下

 <div class="tab-content" style="display: none">
            <dl>
                <dt>影像资料</dt>
                <dd>
                    <div id="post-container" class="container">
                        <div class="page-container">
                            <div id="uploader" class="wu-example">
                                <div class="queueList">
                                    <div id="dndArea" class="placeholder">
                                        <div id="filePicker"></div>
                                        <p>或将照片拖到这里,单次最多可选300张</p>

                                    </div>

无法打开上传图片的选择框

一个图片压缩后size改变造成的无法在队列中删除文件的问题

之前用webuploader做上传,上传成功后如果调接口删除,发现无法再往队列中添加该图。经源码分析,发现问题如下:

控件在图片进入队列时利用图片名称,size,修改时间做了一个hash,用来标记文件是否在队列中。但是由于控件默认启用了压缩,导致压缩后图片尺寸改变,算出的hash和原来不等。造成无法删除,导致再次上传时,控件认为此文件依然存在。

在android上传照片旋转问题

我在android mobile上利用webuploader上传照片,直式照片在预览会自行翻转成正确的显示,但是按上传照片之后依然是显是横向的,请问有没有办法根据预览的显示来存结果到资料夹呢?麻烦了,感谢!

上传器flash版的一个问题

下载的压缩包里面的例子, 如果使用flash版本, 点击flash没有效果 我用的是谷歌浏览器,强制使用flash。
snapshot3

进过调试 发现 flash版本加上

accept : {
                extensions : 'gif,jpg,png',
                mimeTypes : 'image/*'
            },

之后就弹不出文件选择框,去掉之后正常弹出,不知道为什么

如何判断文件是否上传成功?

默认如果啥也不处理,只要有返回数据就认为是成功,就算返回的是错误信息,也认为是成功了。

但是,在认为成功前会派送一个事件uploadAccept,这个事件是用来询问是否上传成功的。在这个事件中你可以拿到上传的是哪个文件,以及对应的服务端返回reponse

uploader.on( 'uploadAccept', function( file, response ) {
    if ( hasError ) {
        // 通过return false来告诉组件,此文件上传有错。
        return false;
    }
});

response是个对象,如果服务器返回是json格式,那么正和你意,都已经解析好了,如果不是json格式,response._raw里面可以拿到原始数据。所以,webuploader对于后端返回的数据格式是没有要求的。

顺序上传

用户选择的不同文件,我能按自己的需求排序后,然后再上传吗?

对于服务器返回json的疑问

请问一下服务器返回json 一定要是这样的格式吗?
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');

不一样的json格式对前端有影响吗?或者说前端跟json绑定吗?

这段代码很巧妙啊

这段代码中对闭包的用法很巧妙,巧妙的实现了调用流程与回调流程的通信 赞一个

var ret = tr.getResponseAsJson() || {},
                        reject, fn;

                    ret._raw = tr.getResponse();
                    fn = function( value ) {
                        reject = value;
                    };

                    // 服务端响应了,不代表成功了,询问是否响应正确。
                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {
                        reject = reject || 'server';
                    }

                    // 如果非预期,转向上传出错。
                    if ( reject ) {
                        tr.trigger( 'error', reject );
                        return;
                    }

                    // 全部上传完成。
                    if ( file.remaning === 1 ) {
                        me._finishFile( file, ret );
                    } else {
                        tr.destroy();
                    }

关于上传文件域和参数

1.请问如何在上传的时候添加多个参数一并发送到后台?
2.可不可以添加参数 修改 file 的name 用来后台接收

这段代码很巧妙啊

这段代码中对闭包的用法很巧妙,巧妙的实现了调用流程与回调流程的通信 赞一个

var ret = tr.getResponseAsJson() || {},
                        reject, fn;

                    ret._raw = tr.getResponse();
                    fn = function( value ) {
                        reject = value;
                    };

                    // 服务端响应了,不代表成功了,询问是否响应正确。
                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {
                        reject = reject || 'server';
                    }

                    // 如果非预期,转向上传出错。
                    if ( reject ) {
                        tr.trigger( 'error', reject );
                        return;
                    }

                    // 全部上传完成。
                    if ( file.remaning === 1 ) {
                        me._finishFile( file, ret );
                    } else {
                        tr.destroy();
                    }

关于并发请求数与整体网络速度的关系研究

简单做了了一个关于并发与网速关系的测试,数据如下:

WIFI

46M                     = 46m
14                      = 14    = 3.2m/s

29.72M                  = 29.72m
8.67                    = 8.67  = 3.4m/s

46M     31M             = 77M
18      13              = 18    = 4.2m/s

46M     31M     26M     = 103M
20      14      14      =   20  = 5.1m/s

WIFI下相同大小文件

31.17M      31.17M      31.17M      31.17M      31.17M      31.17M  = 187.02M
21.89       22.54       21.61       24.71       22.53       22.54   = 24.71 S
1.42m/s     1.38m/s     1.44m/s     1.26m/s     1.38m/s     1.38m/s = 7.56 M/S


31.17M      31.17M      31.17M      31.17M      31.17M              = 155.85M
19.21       19.52       18.68       19.31       20.25               = 20.25 S
1.62m/s     1.59m/s     1.66m/s     1.61m/s     1.53m/s             = 7.69 M/S


31.17M      31.17M      31.17M      31.17M                          = 124.68M
17.42       17.30       16.75       18.52                           = 18.52 S
1.79m/s     1.80m/s     1.86m/s     1.68m/s                         = 6.73 M/S


31.17M      31.17M      31.17M                                      = 93.51M
15.26       15.57       14.97                                       = 15.57 S
2.04m/s     2.00m/s     2.08m/s                                     = 6.00 M/S


31.17M      31.17M                                                  = 62.34M
13.95       14.58                                                   = 14.58 S
2.23m/s     2.13m/s                                                 = 4.27 M/S


31.17M                                                              = 31.17M
12.89                                                               = 12.89 S
2.42m/s                                                             = 2.42 M/S

3G

1.13M                   = 1.13M
24.8                    = 24.8  = 46.66K/S

785.27K                 = 785.27K
16.97                   = 16.97 = 46.27/S 

1.13M   0.77M           = 1.9M
40.15   28.41           = 40.15 = 48.45K/S

3G下相同大小文件

806K                                = 806K
16.72                               = 16.72
48.21k/s                            = 48.21K/S

806K        806K                    = 1612K
31.53       33.34                   = 33.34
25.56k/s    24.17k/s                = 48.35K/S

806K        806K        806K        = 2418K
48.30       47.07       48.66       = 48.66
16.68k/s    17.12k/s    16.56k/s    = 49.69K/S

低网速下,单请求已能达到带宽极值,并发的总体速度与无并发基本一致,因此并发对上传时间的压缩并无正负作用;
高网速下,单个请求未达到带宽极值,并发的总体速度有非常明显的提升,因此并发对上传时间的压缩有正向作用;

由此引发的几个问题需要跟进:

  1. 在高带宽下,单个请求的速度为什么未达到带宽极值,单个请求的速度受哪些条件影响?
  2. 并发时的请求数如何控制能够达到最优的速度?
  3. 在实现chunk上传时,并发请求数与并发发送的数据量如何控制能够达到最优的速度?

如何实现秒传与断点续传

因为这是小众需求,所以默认没有做在webuploader里面,而只是提供hook接口,让用户很简单的扩展此功能。

那么,都有哪些重要的hook接口呢?

  • before-send-file 此hook在文件发送之前执行
  • before-file 此hook在文件分片(如果没有启用分片,整个文件被当成一个分片)后,上传之前执行。
  • after-send-file 此hook在文件所有分片都上传完后,且服务端没有错误返回后执行。
  • ...

对于秒传来说,其实就是文件上传前,把内容读取出来,算出md5值,然后通过ajax与服务端验证进行验证, 然后根据结果选择继续上传还是掉过上传。

像这个操作里面有两个都是异步操作,文件内容blob读取和ajax请求。所以这个handler必须是异步的,怎样告诉组件此handler是异步的呢?只需要在hanlder里面返回一个promise对象就可以了,这样webuploader就会等待此过程,监听此promise的完成事件,自动继续。

以下是此思路的简单实现。

Uploader.register({
    'before-send-file': 'preupload'
}, {
    preupload: function( file ) {
        var me = this,
            owner = this.owner,
            server = me.options.server,
            deferred = WebUploader.Deferred();

        owner.md5File( file.source )

            // 如果读取出错了,则通过reject告诉webuploader文件上传出错。
            .fail(function() {
                deferred.reject();
            })

            // md5值计算完成
            .then(function( md5 ) {

                // 与服务安验证
                $.ajax(server, {
                    dataType: 'json',
                    data: {
                        md5: ret
                    },
                    success: function( response ) {

                        // 如果验证已经上传过
                        if ( response.exist ) {
                            owner.skipFile( file );

                            console.log('文件重复,已跳过');
                        }

                        // 介绍此promise, webuploader接着往下走。
                        deferred.resolve();
                    }
                });
            });

        return deferred.promise();
    }
});

关于断点续传

其实就是秒传分片,跟秒传整个文件是一个思路。关于md5验证这块,可以ajax请求验证,也可以在文件秒传验证的时候,把已经成功的分片md5列表拿到,这样分片验证的时候就只需要本地验证就行了,减少请求数。

具体实现和思路请查看这里#139

asp.net

请问有asp.net的例子吗,server的请求,在asp.net中如何获取到上传 的文件

jQuery 1.7 浏览器卡死,复现率100%

测试环境:WIN8+Chrome 、 WIN8+IE10、WIN8+firefox
按照Getting Started第一个例子,不管是自动还是手动触发上传,皆出现脚本运行时间过长,浏览器卡死现象。并未正确触发 uploadProgress 事件,控制台也没有报错。

auto: true 时不能生成缩略图,手动时可以生成缩略图。

自己通过grunt编译出错

$ grunt dist Running "build:all" (build) task

File 'dist/webuploader.js' created.

Running "build:flashonly" (build) task

File 'dist/webuploader.flashonly.js' created.

Running "build:html5only" (build) task

File 'dist/webuploader.html5only.js' created.

Running "build:withoutimage" (build) task

File 'dist/webuploader.withoutimage.js' created.

Running "build:custom" (build) task

File 'dist/webuploader.custom.js' created.

Running "uglify:static_mapping" (uglify) task
{ message: 'Invalid hex-character pattern in string',
line: 4429,
col: 8,
pos: 135907,
stack: 'Error\n at new JS_Parse_Error (f:\Users\Jack Zhang\Documents\Gi
tHub\webuploader\node_modules\grunt-contrib-uglify\node_modules\uglify-js
lib\parse.js:196:18)\n at js_error (f:\Users\Jack Zhang\Documents\GitHub
\webuploader\node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib
\parse.js:204:11)\n at parse_error (f:\Users\Jack Zhang\Documents\GitHub
\webuploader\node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib
parse.js:306:9)\n at hex_bytes (f:\Users\Jack Zhang\Documents\GitHub\web
uploader\node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib\pars
e.js:358:17)\n at read_escaped_char (f:\Users\Jack Zhang\Documents\GitHub
\webuploader\node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib
\parse.js:347:49)\n at f:\Users\Jack Zhang\Documents\GitHub\webuploader
\node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:384:
27\n at f:\Users\Jack Zhang\Documents\GitHub\webuploader\node_modules
grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:516:24\n at Obje
ct.next_token [as input](f:\Users\Jack Zhang\Documents\GitHub\webuploader
node_modules\grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:543:
36)\n at next (f:\Users\Jack Zhang\Documents\GitHub\webuploader\node_mo
dules\grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:649:25)\n
at expect_token (f:\Users\Jack Zhang\Documents\GitHub\webuploader\node_mo
dules\grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:682:20)\n
at expect (f:\Users\Jack Zhang\Documents\GitHub\webuploader\node_modules
\grunt-contrib-uglify\node_modules\uglify-js\lib\parse.js:687:36)\n at f:
\Users\Jack Zhang\Documents\GitHub\webuploader\node_modules\grunt-contrib
-uglify\node_modules\uglify-js\lib\parse.js:1192:9' }

Uglifying source dist/webuploader.js failed.
Warning: Uglification failed.
Invalid hex-character pattern in string.
Line 4429 in dist/webuploader.js
Use --force to continue.

Aborted due to warnings.

这是为什么?

关于上传失败 返回数据

on('uploaderError')的时候 返回的reason一直是 'http' 不是我返回的json字符串 ,试了那个uploadAccept好像也没用

关于IE9下的问题

在我下载的最新版程序中的第120行左右
代码如下

function bindFn( fn, context ) {
            return Function.prototype.bind ? fn.bind( context ) : function() {
                return fn.apply( context, arguments );
            };
        }

这段代码在IE10 谷歌 火狐上都没问题唯独在IE9以及有问题
说对象没有bind方法
仔细看看这段代码不难发现确实有漏洞
假如 原生的函数具有bind方法 但是假如传入的fn却是个对象就有问题, 恰恰在IE9上就有对象传进来,我找了很久没找到,同样的代码其他都没问题唯独这个IE9

还有对比之前的代码, 是下面的写法,貌似没问题

function bindFn( fn, context ) {
            return fn.bind ? fn.bind( context ) : function() {
                return fn.apply( context, arguments );
            };
        }

附注 咱们的官网的例子也有问题 在IE9下的截图
qq20140115093618
qq20140115094023

如何让上传的请求携带其他参数信息?

目前有两种设置的方法。

  1. 全局设置,就是每个文件上传的时候都会携带的。通过修改options.formData来控制。比如如下demo添加一个uid=123。

    // 初始化的时候直接添加
    var uploader = new WebUploader.Uploader({
        ...
        formData: {
            uid: 123
        }
        ...
    });
    
    // 初始化以后添加
    uploader.options.formData.uid = 123;
  2. 局部设置,给每个独立的文件上传设置。通过绑定一个uploadBeforeSend事件来添加。

    uploader.on( 'uploadBeforeSend', function( block, data ) {
        // block为分块数据。
    
        // file为分块对应的file对象。
        var file = block.file;
    
    
        // 修改data可以控制发送哪些携带数据。
        data.uid = 123;
    
        // 将存在file对象中的md5数据携带发送过去。
        // data.fileMd5 = file.md5;
    
        // 删除其他数据
        // delete data.key;
    });

支持用 requirejs 以 package 的方式加载

比如 zrender,我声明一个 package,指定路径和入口文件,即可使用整个 zrender 的功能。

{
  packages:[{
    name: 'zrender',
    location: '/zrender/src',
    main: 'zrender'
  }]
}

但是 webuploader 没有这样一个入口文件,可以靠 requirejs 去加载全部文件。

希望支持。

PS. 简单概括,就是 WebUploader 可以用 r.js 打包。

版本发布建议

建议给正式发布的版本打个tag,标注版本号,这样就能直接在"releases"标签下面下载到对应的版本了。不过,这样发布的是 source 版本。

对于用于生产环境的版本需要手工打个包上传到对应的tab release内。建议用grunt脚本直接打包。

关于文件对话框关闭的时候事件

开发人员您们好,可以加上这个特性吗? 就是在对话框关闭的时候派发一些错误信息的事件,比如文件大小超出或者类型错误等等,当前默认行为貌似是毫无反应

SCRIPT438: 对象不支持此属性或方法 webUploader.js, 行5293 字符17

在IE8环境下,开始上传文件时

this.flashExec = function(comp, fn) {
    var flash = me.getFlash(),
        args = Base.slice(arguments, 2);

    return flash.exec(this.uid, comp, fn, args); //此处报错,应该是没有取到flash对象
};

现页面引用js:

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="webUploader.js"></script>

不知是何原因?

图片压缩问题

同学,你们好, 本人在使用你们上传组件的时候发现了,上传jpg图片时候,组件会对图片进行压缩,但是你们在删除文件的时候,获取hash的时候跟文件大小有关系,导致被压缩的文件两次hash值不一样。删除失败。

关于拖拽上传 文件判断过于严格的一个问题修复

由于有的文件type为空:比如 .zip .url 或者没有扩展名的也是文件。
我做了入下调整:

        canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);
            for ( i = 0, len = files.length; i < len; i++ ) {
                file = files[i];
                // change by warlee 
                // if ( file.type ) {
                //     results.push( file );
                // } else if ( !file.type && canAccessFolder ) {
                //     promises.push( this._traverseDirectoryTree(
                //             items[ i ].webkitGetAsEntry(), results ) );
                // }

                if (items[i].webkitGetAsEntry()!=null && items[i].webkitGetAsEntry().isDirectory) {//if folder
                    if(canAccessFolder){
                        promises.push( this._traverseDirectoryTree(
                            items[ i ].webkitGetAsEntry(), results ) );
                    }
                }else{//is file
                    results.push(file);
                }
            }   



         _traverseDirectoryTree: function( entry, results ) {
            var deferred = Base.Deferred(),
                me = this;   
            if (entry.isFile ) {
                entry.file(function( file ) {
                    //== change by warlee 
                    //file.type && results.push( file );
                    results.push( file );
                    deferred.resolve( true );
                });
            } 

中文文件无法上传或者乱码问题?

用示例中的例子上传文件,上传中文文件出现无法上传或者出现上传文件名乱码。而大文件上传文件名自动变成“”file_”什么的,什么原因?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.