原 荐 七牛 JSSDK 配置+常见问题

作者:汪娇娇

时间:2017年7月7日

一、铺垫

依靠七牛上传图片,其实有很多方法,先说说有哪些方法,以及这些方法各自的优缺点吧(移动端)。

way1:前端只负责选择图片,然后将图片传给服务端,服务端再传给七牛,再将地址返给前端展示。

优:可以控制上传图片到七牛的时机,不浪费七牛的存储空间;

缺:浪费自己服务器的带宽,并且周周转转,耗时长,麻烦。

way2:前端发通知让客户端来上传图片到七牛。

优:前端不需要处理太多东西,只需要给客户端发一个通知。

缺:选一张图片就上传了一张,如果多次选择,会浪费七牛存储空间。

way3:前端集成七牛的jssdk。

优:可以控制上传图片到七牛的时机,不浪费七牛的存储空间;不通过服务端,所以不会消耗服务器带宽;不通过客户端,所以不需要集成javascriptBridge和客户端通信。

缺:路漫漫其修远兮,需要自己去踩坑。。。。

二、七牛 JSSDK

下面正式进入七牛JSSDK:

1、把该引入的文件都引入了。

三个文件:

(1)产品环境:plupload、plupload.full.min.js、qiniu.min.js

(2)开发调试:plupload.dev.js 、moxie.js、qiniu.js

2、初始化uploader 。

 var uploader = Qiniu.uploader({
      runtimes: 'html5,flash,html4',      // 上传模式,依次退化
      browse_button: 'pickfiles',         // 上传选择的点选按钮,必需,id名
      uptoken : '<Your upload token>', // uptoken是上传凭证,由其他程序生成
      get_new_uptoken: false,             // 设置上传文件的时候是否每次都重新获取新的uptoken
      // unique_names: true,              // 默认false,key为文件名。若开启该选项,JS-SDK会为每个文件自动生成key(文件名)
      // save_key: true,                  // 默认false。若在服务端生成uptoken的上传策略中指定了sava_key,则开启,SDK在前端将不对key进行任何处理
      domain: '<Your bucket domain>',     // bucket域名,下载资源时用到,必需
      container: 'container',             // 上传区域DOM ID,默认是browser_button的父元素
      max_file_size: '100mb',             // 最大文件体积限制
      flash_swf_url: 'path/of/plupload/Moxie.swf',  //引入flash,相对路径
      max_retries: 3,                     // 上传失败最大重试次数
      dragdrop: true,                     // 开启可拖曳上传
      drop_element: 'container',          // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传
      chunk_size: '4mb',                  // 分块上传时,每块的体积
      auto_start: true,                   // 选择文件后自动上传,若关闭需要自己绑定事件触发上传
      init: {
          'FilesAdded': function(up, files) {
              // 文件添加进队列后,处理相关的事情
          },
          'BeforeUpload': function(up, file) {
                 // 每个文件上传前,处理相关的事情
          },
          'UploadProgress': function(up, file) {
                 // 每个文件上传时,处理相关的事情
          },
          'FileUploaded': function(up, file, info) {
                 // 每个文件上传成功后,处理相关的事情
                 // 其中info是文件上传成功后,服务端返回的json,形式如:
                 // {
                 //    "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",
                 //    "key": "gogopher.jpg"
                 //  }
                 // 查看简单反馈
                 // var domain = up.getOption('domain');
                 // var res = JSON.parse(info);
                 // var sourceLink = domain +"/"+ res.key; 获取上传成功后的文件的Url
          },
          'Error': function(up, err, errTip) {
                 //上传出错时,处理相关的事情
          },
          'UploadComplete': function() {
                 //队列文件处理完毕后,处理相关的事情
          },
          'Key': function(up, file) {
              // 若想在前端对每个文件的key进行个性化处理,可以配置该函数
              // 该配置必须要在unique_names: false,save_key: false时才生效
              var key = "jojojo/" + file.id;  //可以加上自己设定好的前缀(归类好了,自己易管理)
              return key;
          }
      }
  });

三、常见问题

1、uptoken

uptoken由服务端提供。

uptoken(上传凭证)、uptoken_url(获取上传凭证的地址)、uptoken_func(获取uptoken的过程)三个参数只要有一个被设置就ok。

如果提供了多个,优先级:uptoken > uptoken_url > uptoken_func。

推荐使用uptoken,服务端可以设置一些权限,更安全;使用uptoken_url,相当于将这个接口直接暴露出去,存在安全隐患。

uptoken : '<Your upload token>', // uptoken是上传凭证,由其他程序生成
uptoken_url: '/uptoken',         // Ajax请求uptoken的Url,强烈建议设置(服务端提供),格式:{"uptoken":"<upload token>"}
uptoken_func: function(){        // 在需要获取uptoken时,该方法会被调用
      // do something
      return uptoken;
},

2、上传单张图片

将multi_selection设置为false就可以了。

multi_selection: false,

但有的webview并不支持这个属性,依旧可以选择多张图片,特殊情况特殊处理。

在FileAdded函数中处理:

'FilesAdded': function(up, files) {
      plupload.each(files, function(file) {
            // 针对multi_selection失效时的处理办法:无论选多少个,只留一个
            if(up.files.length > 1){
                   up.removeFile(up.files[0]);  //移除多余的文件
            }
      });
},

3、图片加入队列时就实现预览(不是上传完成后)

都知道上传完成后,会获取到图片的一个链接,这样很容易实现展示。但如果想在图片加入队列时就预览图片,稍稍麻烦点,但也不是没有办法。

在FileAdded函数中处理:

'FilesAdded': function(up, files) {
      plupload.each(files, function(file) {
            //针对加入队列时,而不是上传完成后才可以预览图片的处理办法
            var preloader = new mOxie.Image(); 
            preloader.onload = function() { 
                 $('body').append('<img src="'+preloader.getAsDataURL()+'">');
            };
            preloader.load( file.getSource() ); 
      });
},

4、 Android 自带的 Webview 对JS SDK不支持

Android里点击“选择文件”按钮没有反应,这是Webview 对 JS 不是很支持造成的,解决方法:要求Android客户端引入七牛的Webview ,jar包地址:

https://o8qpi53g2.qnssl.com/Android-AdvancedWebView.jar

使用方法请参考:

private AdvancedWebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     mWebView = (AdvancedWebView) findViewById(R.id.webview);
     mWebView.setListener(this, this);
     mWebView.loadUrl("http://jssdk.demo.qiniu.io/");
}

5、取消自动上传

将auto_start设置为false,绑定自定义的事件触发上传。

auto_start: false,
document.getElementById("btn").onclick = function(){
     uploader.start();
}

但这其中还是会存在问题的。

比如说,你上传文件后,要把上传后的链接和其他一些数据传给服务端,现在的逻辑应该是把上传给服务器的操作放在FileUploaded里面,这样才能保证拿到链接。

但如果你选定一张图片后,只是改变其他数据的变化,那你每次都要uploader.start()吗?但事实是,只要你选定一张图片后,uploader.start()只会生效一次,后来就不生效了,那放在uploader.start()里的操作就不执行了,这并不是我们想要的结果。

那就做个判断,如果再选择另外一张图片了,就执行uploader.start(),如果一直没再选择另外一张图片,就直接执行和服务端的交互。那问题是,怎么判断别人有没有选择另外一张图片呢?

用标记法。标记一个flag=0(初始状态),选择图片后,在FileAdded里设置flag=1,代表进入新的图片。上传完成后,也就是在fileUploaded里设置flag=0,代表图片上传完成,只要没有新图片加入,flag一直为0,就可以直接执行和服务端的交互。一旦新图片加入队列,flag=1,就可以执行uploader.start()了。

6、限制上传文件的类型

// 可以使用该参数来限制上传文件的类型,大小等,该参数以对象的形式传入,它包括三个属性:
filters : {
    max_file_size : '100mb',
    prevent_duplicates: true,   //是否可以上传重复的图片,true:不能重复,false:可以重复
    mime_types: [
        {title : "flv files", extensions : "flv"} // 限定flv后缀上传格式上传
        {title : "Video files", extensions : "flv,mpg,mpeg,avi,wmv,mov,asf,rm,rmvb,mkv,m4v,mp4"}, // 限定flv,mpg,mpeg,avi,wmv,mov,asf,rm,rmvb,mkv,m4v,mp4后缀格式上传
        {title : "Image files", extensions : "jpg,gif,png"}, // 限定jpg,gif,png后缀上传
        {title : "Zip files", extensions : "zip"} // 限定zip后缀上传
    ]
},

6、修改上传文件命名

将unique_names和save_key都设置为false,并在Key函数中做相关处理。

unique_names: false,
save_key: false, 
'Key': function(up, file) {
     var key = "jojojo/" + file.id;  //可以加上你的个性前缀(好归类,自己好管理)
     return key;
}

假设domain是:https://www.jojojojo.com

默认得到的文件名是:https://www.jojojojo.com/h53434d8h3jj0

修改之后的文件名是:https://www.jojojojo.com/jojojo/h53434d8h3jj0

修改之后的有了归类,更容易管理。

7、关于多个按钮选择文件的 Demo

很多用户都在问 JSSDK 多文件选择的 Demo,其实只需要在 main.js 文件里多 new 几个 Uploader 对象,然后在主页上写好对应的上传按钮就可以了。

main.js 里面多 new 几个 uploader 对象:

$(function() {
    var uploader = Qiniu.uploader({
        runtimes: 'html5,flash,html4',
        browse_button: 'pickfiles',
        container: 'container',
        drop_element: 'container',
        max_file_size: '100mb',
        flash_swf_url: 'js/plupload/Moxie.swf',
        dragdrop: true,
        chunk_size: '4mb',
        uptoken:'um6IEH7mtwnwkGpjImD08JdxlvViuELhI4mFfoeL:79ApUIePTtKIdVGDHJ9D9BfBnhE=:eyJzY29wZSI6ImphdmFkZW1vIiwiZGVhZGxpbmUiOjE0NTk4ODMyMzV9Cg==',
        // uptoken_url: $('#uptoken_url').val(),  //当然建议这种通过url的方式获取token
        domain: $('#domain').val(),
        auto_start: false,
        init: {
            'FilesAdded': function(up, files) {
                $('table').show();
                $('#success').hide();
                plupload.each(files, function(file) {
                    var progress = new FileProgress(file, 'fsUploadProgress');
                    progress.setStatus("等待...");
                });
            },
            'BeforeUpload': function(up, file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
                if (up.runtime === 'html5' && chunk_size) {
                    progress.setChunkProgess(chunk_size);
                }
            },
            'UploadProgress': function(up, file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                var chunk_size = plupload.parseSize(this.getOption('chunk_size'));

                progress.setProgress(file.percent + "%", file.speed, chunk_size);
            },
            'UploadComplete': function() {
                $('#success').show();
            },
            'FileUploaded': function(up, file, info) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                progress.setComplete(up, info);
            },
            'Error': function(up, err, errTip) {
                $('table').show();
                var progress = new FileProgress(err.file, 'fsUploadProgress');
                progress.setError();
                progress.setStatus(errTip);
            }
        }
    });

    uploader.bind('FileUploaded', function() {
        console.log('hello man,a file is uploaded');
    });

    $('#up_load').on('click', function(){
        uploader.start();
    });
    $('#stop_load').on('click', function(){
        uploader.stop();
    });

    var Q2 = new QiniuJsSDK();
    var uploader2 = Q2.uploader({
        runtimes: 'html5,flash,html4',
        browse_button: 'pickfiles2',
        container: 'container2',
        drop_element: 'container2',
        max_file_size: '100mb',
        flash_swf_url: 'js/plupload/Moxie.swf',
        dragdrop: true,
        chunk_size: '4mb',
        uptoken:'um6IEH7mtwnwkGpjImD08JdxlvViuELhI4mFfoeL:79ApUIePTtKIdVGDHJ9D9BfBnhE=:eyJzY29wZSI6ImphdmFkZW1vIiwiZGVhZGxpbmUiOjE0NTk4ODMyMzV9Cg==',
        // uptoken_url: $('#uptoken_url').val(),  //当然建议这种通过url的方式获取token
        domain: $('#domain').val(),
        auto_start: false,
        init: {
            'FilesAdded': function(up, files) {
                $('table').show();
                $('#success').hide();
                plupload.each(files, function(file) {
                    var progress = new FileProgress(file, 'fsUploadProgress');
                    progress.setStatus("等待...");
                });
            },
            'BeforeUpload': function(up, file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
                if (up.runtime === 'html5' && chunk_size) {
                    progress.setChunkProgess(chunk_size);
                }
            },
            'UploadProgress': function(up, file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                var chunk_size = plupload.parseSize(this.getOption('chunk_size'));

                progress.setProgress(file.percent + "%", file.speed, chunk_size);
            },
            'UploadComplete': function() {
                $('#success').show();
            },
            'FileUploaded': function(up, file, info) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                progress.setComplete(up, info);
            },
            'Error': function(up, err, errTip) {
                $('table').show();
                var progress = new FileProgress(err.file, 'fsUploadProgress');
                progress.setError();
                progress.setStatus(errTip);
            }
        }
    });

    uploader2.bind('FileUploaded', function() {
        console.log('hello man 2,a file is uploaded');
    });
    $('#up_load2').on('click', function(){
        uploader2.start();
    });
    $('#stop_load2').on('click', function(){
        uploader2.stop();
    });

相应的 index.html 文件加入相关按钮:

<div id="container">
        <a class="btn btn-default btn-lg " id="pickfiles" style="width:160px" href="#" >
            <i class="glyphicon glyphicon-plus"></i>
            <span>选择文件</span>
        </a>

        <a class="btn btn-default btn-lg " id="up_load" style="width:160px" href="#" >
            <span>确认上传</span>
        </a>  

        <a class="btn btn-default btn-lg " id="stop_load" style="width:160px" href="#" >
            <span>暂停上传</span>
        </a> 
    </div>

<div id="container2">
        <a class="btn btn-default btn-lg " id="pickfiles2" style="width:160px" href="#" >
            <i class="glyphicon glyphicon-plus"></i>
            <span>选择文件</span>
        </a>

        <a class="btn btn-default btn-lg " id="up_load2" style="width:160px" href="#" >
            <span>确认上传</span>
        </a>  

        <a class="btn btn-default btn-lg " id="stop_load2" style="width:160px" href="#" >
            <span>暂停上传</span>
        </a> 
    </div>
</div>

以上是我遇见的问题,其他问题可以参考七牛JSSDK官网:

https://developer.qiniu.com/kodo/sdk/1283/javascript#6

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菜鸟计划

angularjs MVC、模块化、依赖注入详解

一、MVC ? <!doctype html> <html ng-app> <head> <meta charset="utf-8"> ...

37960
来自专栏京东技术

必须掌握的ADB命令 | 让你的测试事半功倍

ADB的全称是Android Debug Bridge,是一个与模拟器或者连接设备通讯的桥梁。ADB是CS结构包含三个部分:

1.9K40
来自专栏技术博文

H5缓存机制浅析

1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性。离线存储(也可称为缓存机制)是其中一个非常重要的特性。H5 引入的离...

45080
来自专栏运维小白

Linux基础(day53)

12.21 php-fpm的pool php-fpm的pool目录概要 vim /usr/local/php/etc/php-fpm.conf//在[globa...

207100
来自专栏Petrichor的专栏

python: pyenv 指令备忘录

10520
来自专栏散尽浮华

进程管理利器-supervisor部署记录

一、简单介绍 supervisor是用来管理进程的一个工具,止于为什么要用supervisor,是因为相对于linux传统的进程管理方式来说,它有很多的优势: ...

42980
来自专栏Web 开发

各种Kill跨域Boss的方法

对于JSON数据,可以很容易的获取。不过在结合Android的WebView后会存在一个很严重的问题。

7900
来自专栏云计算教程系列

使用CVM搭建FileRun私人网盘

FileRun是由PHP编写的文件管理器和文件共享程序,可帮助您访问,整理,查看和编辑文件。您可以将其与Office文档,照片,音乐等文件一起使用。在本教程中,...

485110
来自专栏Coding迪斯尼

java开发操作系统:启动任意多控制台窗口

13710
来自专栏linux、Python学习

Linux基础教程之linux文件权限深度解读

基本命令—— 1.cut : cat /etc/passwd | cut -d’:’ -f7| uniq -c| sort -nr

10000

扫码关注云+社区

领取腾讯云代金券