专栏首页jojo的技术小屋原 荐 七牛 JSSDK 配置+常见问题

原 荐 七牛 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 条评论
登录 后参与评论

相关文章

  • 原 WebViewJavascriptBr

    作者:汪娇娇 时间:2017年8月3日 H5和客户端(IOS、安卓)想要交互怎么办(手动头疼)? 答案是肯定的,必要的时候还是要借助一定的工具啦。 我主要研究的...

    jojo
  • 转 前端代码异常日志收集与监控

    ☞ 收集日志的方法 平时收集日志的手段,可以归类为两个方面,一个是逻辑中的错误判断,为主动判断;一个是利用语言给我们提供的捷径,暴力式获取错误信息,如 try....

    jojo
  • js模块化编程之彻底弄懂CommonJS和AMD/CMD!(转)

    答:因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。 但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写...

    jojo
  • The Clean Architecture in PHP 读书笔记(三)The Clean Architecture in PHP 读书笔记(三)

    这5大原则最初是由Robert C. Martin提出,这些原则主要解决了下面两个问题:

    zhuanxu
  • 神秘的Waymo一反常态,CVPR现场发布大型自动驾驶数据集

    目前,自动驾驶领域已经出现很多数据集,例如 KITTI、Oxford、Cityscape、nuScenes、BDD100K 等。

    机器之心
  • JS常用设计模式解析01-单例模式

    考虑实现如下功能,点击一个按钮后出现一个遮罩层。 原始办法:我们只需要实现一个创建遮罩层的函数并将其作为按钮点击的回调事件即可。如下:

    love丁酥酥
  • JavaScript的IIFE(即时执行方法)

    前面的话   严格来讲,IIFE并不是闭包,因为它并不满足函数成为闭包的三个条件。但一般地,人们认为IIFE就是闭包,毕竟闭包有多个定义。本文将详细介绍IIFE...

    庞小明
  • JavaScript模式 读书笔记三

    函数是第一类对象 first-class object,可以作为带有属性和方法的值以及参数进行传递。

    lilugirl
  • jQuery调取微信摄像头代码记录

    我们在写不管是小程序还是微信公众号的时候,调取微信的摄像头的接口都是避免不了的,那么调取微信的摄像头的接口还是需要注意一些问题的,不然可能调取不成功,下面我简单...

    何处锦绣不灰堆
  • facebook的大剧还在演,吃瓜的小编默默压压惊

    相信大家都已经知道了 5000万数据被泄露 Facebook这次算是玩儿大了 ? 最新报道整理: 据报道,泄露的5000万Facebook用户信息被数据分析公司...

    安恒信息

扫码关注云+社区

领取腾讯云代金券