在Vant组件里面使用upload组件,上传视频到七牛

3,325 阅读3分钟

  这两天收到一个很紧急的需求,需要在一天后上线。需求是要在app上面实现一个反馈的表单,表单里面有上传视频的功能。讲道理,刚收到这个需求的时候,觉得应该不难。但是在实现的过程中感觉还是有点曲折,于是在把这个项目交付完了以后,写下来,记录一些心得。

寻找调用可以拿到视频的api

  开始动手的时候,在交互库里寻找了一番,发现了一个很严重的问题:交互库这边调用图库的方法,只能拿到图片。这就很难受了呀,于是开始寻找可以拿到图库的api。起初,第一个想到的是

<input  type = “file” />

因为 input 标签在里面有个api=>type,这个是可以获取到文件的类型,是可以拿到视频的。于是在浏览器上面尝试了一下,发现果然是可以,于是在项目app里面搞了一下测试页面,发现了问题:ios可以看到视频,安卓的不行。 裂开了啊。

企业微信截图_16403088967717.png

  于是想着换其他api。之前在其他页面试过有赞的组件,感觉还可以。而且里面也有上传的组件。于是,也测试了一下。发现了一样的问题:ios可以看到视频,安卓的不行,看了一下文档,有赞用的也是原生的 input 标签,裂开了啊。我在其他的app上面尝试了一下,安卓和ios都是可以拿到视频的,那就是结论只有一个:我们的项目app没有打开这个对应的权限。那没办法了啊,赶紧向产品经理抛开问题,app改动再上集成是来不及的,产品经理已同意,并说后续在让app迭代这个方面的功能,并说样式方面我相信你,那我必然优先选择有赞了!

企业微信截图_16402613469746.png

开始开发,第一个版本(以base64格式上传视频)

  首先总结一下这个开发的流程,上传视频到七牛之前,要先从后端哪里拿到一个对象,对象里面有 { token,url },token赋值给你要上传的文件接口上面,url是上传地址,然后上传到七牛。第一次,后端给的上传接口是之前上传图片到七牛的接口,是将图片转为base64上传。

  这是一个gulp的的项目,之前有仙人在这里面大胆的引用了vue,于是乎,我也不敢乱调整,就在里面使用vue开发了。

  引入有赞方法这里不做赘述,放上有赞快速上手的地址:

[youzan.github.io/vant/#/zh-C…]   

上传视频的HTML:

<van-uploader v-model="fileList" accept="image/*,video/*" max-count='3' :after-read="afterRead" multiple />
// accept 接受的类型
// max-count 最大上传文件数
// after-read 读取文件后的回调

写一个获取token的回调函数:

getToken(typeObj, success, fail) {
     const param = {
           url: `${baseUrl}/file/getUpload/`, // 上传的地址
           method: "post",
           body: JSON.stringify({   // 对应的参数
               filename:“”
           }), 
      }; 
      xxxxBridge.request(param, (res) => {  
      // console.info("getToken.res=", res);
      if (res.code === "xxxxxx") {
           success && success(res.data);
      } else {
           fail && fail(res);
      }
      });
   },

上传到七牛:

有赞的组件提供了一个afterRead的函数,可以拿到文件,以及base64码还是有点方便的

afterRead(file) {
            file.status = "uploading";
            file.message = "上传中...";
            vm.getToken(
                vm.getType(file.file),
                function (data) {
                    if (!data) {
                        return xxxxBridge.toast("没有获取到文件的token");
                    }
                    const url = data.url + "/putb64/xxxxxx" || "https://xxxx.qiniup.com/putb64/xxxxxx;
                    const xhr = new XMLHttpRequest();
                    const base64Filter = vm.base64Filter(file.content) // 获取base64码后面逗号以后的码
                    xhr.onreadystatechange = () => {
                        if (xhr.readyState === 4) {
                            file.status = "done";
                            file.message = "已上传";
                            xxxxBridge.jsLog(xhr.responseText);
                            const response = JSON.parse(xhr.responseText);
                            // console.log('response:'+ JSON.stringify(response))
                        }
                    };
                    xhr.open("POST", url, true);
                    xhr.setRequestHeader("Content-Type", "application/octet-stream");
                    xhr.setRequestHeader("Authorization", "UpToken " + data.token);
                    xhr.send(base64Filter);
                },
                function (error) {
                    console.error(error);
                    xxxxBridge.toast("上传失败");
                }
            );
        },
  base64Filter(str){
            const base64Arr = str.split(',')
            return base64Arr[1]
        },

  测试一下,成功的。但是上传的属实是 有点慢,我上传了一个30M大小的视频,差不多需要1分钟30秒。

  输出了上传一下文件,打了一下日志,发现转为base64码后大小增加了原体积的一半,这属实是有点大啊。

base64码大小:

企业微信截图_16402632363609.png 视频实际大小:

企业微信截图_16402633256259.png

第二个版本(表单形式上传)

  接着和后端讨论了一下,用表单的形式上传视频。但是测试表单的过程中,发现一直请求不通服务器。找了很久原因,才发现交互库的请求方法竟然不支持传表单。很难受,之前的封装的请求方法的表头和上次表单的表单不一样,重新再封装一个请求方法

function sendAjaxQiNiu(options) {
    var request = new XMLHttpRequest();
    request.open(options.method, options.url);
    if (!options.headers) {
​
        request.setRequestHeader('Content-Type', 'application/json');
    }
    request.send(options.data);
    request.onreadystatechange = function () {
        if (request.readyState === 4) {
            if (request.status >= 200 && request.status < 300) {
                var data = JSON.parse(request.response);
                var headers = request.getAllResponseHeaders();
                options.success && options.success(data, headers);
            } else if (request.status >= 400) {
                options.fail && options.fail(request);
            }
        }
    };
}

获取token,上传

afterRead(file) {
            file.status = "uploading";
            file.message = "上传中...";
            var token = '';
            var p = {
                url: `${baseUrl}/smartwatch/xxxxxxxxxxxxx`,
                method: 'GET',
            }
            xxxxBridge.request(p, function (res) {
                if (res.code === 'xxxxxx') {
                    token = res.data.uploadToken;
                    var formData = new FormData();
                    formData.append('file', file.file);
                    formData.append('token', token);
                    sendAjaxQiNiu({
                        url: `https://upload.qiniup.com/xxxxxxxxxxx`,
                        method: 'POST',
                        headers: {
                            'Content-Type': 'multipart/form-data'  // 注意:这是上传表单的表头
                        },
                        data: formData,
                        success: function (res) {
                            file.status = "done";
                            file.message = "已上传";
                            const response = res
                        },
                    })
                }
            }, )
        },

ok,上传效率比之前明显快很多。大家有其他可以拿到视频的方法,欢迎大家给点建议。

补说一句,千万不要接紧急的需求。特别是原先不是你开发的项目,并且交互库不支持的情况下,要兼容很多东西。看似这样上面这样轻描淡写,真的联调时间,在加上其他样式和测试时间乱七八遭,一套流程下来,加班是必然的

企业微信截图_16402645806273.png