Web端直传实践

场景概述

VOD 用户通过Web上传,是VOD使用需求中很典型的一种应用场景。在该场景下,用户通常采用应用服务器中转的模型进行文件上传。

  1. 用户先将文件通过Web上传到应用服务器;
  2. 应用服务器再将文件上传到VOD。

这个模型的优点比较明显:

  1. 客户端和 VOD 服务器没有任何交互工作,所有和 VOD 的交互都由服务器完成,非常简单和安全;
  2. 服务器可以精确控制用户的行为,添加各种自定义流程。

但是这个模型的缺点也显而易见:

  1. 上传速度慢。因为需要经过应用服务器中转,与客户端数据直传到 VOD 相比,网络传送增加了一倍。
  2. 扩展性差。随着用户数量的增加,应用服务器可能成为传输瓶颈。
  3. 成本高。应用服务器的部署和维护需要一定成本,如客户端数据直传到VOD,将节省应用服务器的开销,且目前VOD上传的流量是免费的。

如果您的应用需要符合这个场景的话,我们推荐您使用"bce-bos-uploader"工具实现客户端直传VOD的方式。

bce-bos-uploader

Baidu Cloud Engine BOS Uploader(bce-bos-uploader)是百度智能云基于Javascript SDK开发的一个ui组件,为了方便用户开发web直传应用而专门提供的,使用该工具用很少的几行代码就可以完成跟BOS服务的对接。由于 VOD 服务依赖和集成了BOS服务,所以bce-bos uploader的一个git分支提供了一个3in1页面,对一个已经开启了BOS、VOD、DOC服务的用户,根据源文件类型智能的上传到BOS、VOD或者DOC服务。

本文重点讲述如何在3in1页面中直传VOD,用户可以根据实际需要对此3in1功能和界面进行自定义修改,详细操作参见在浏览器中直接上传文件到VOD

bce-bos-uploader的demo操作界面如下:

image.png

支持的浏览器

基于Xhr2和File API,可以支持IE10+, Firefox,Chrome和Opera最新版。
借助PostObject接口,可以支持IE低版本(6,7,8,9),详细请参见:通过PostObject接口处理IE低版本

签名方式

bce-bos-upload支持默认、STS、PostObject三种签名方式。

默认签名方式即使用AK/SK签名方式在浏览器中直接上传文件到 VOD 中。通过浏览器直传文件到VOD服务器的时候,如果把AK和SK暴露在页面中,会引发安全性的问题。攻击者获取了AK和SK,可以对VOD甚至百度智能云其他服务上面的数据进行任意的操作。这模式仅可用于开发期间进行本地测试,请勿在生产环境中使用。

使用STS签名更安全灵活,它可以对用户的使用权限进行灵活、精确地控制,而且不必每次请求都调用后端接口,在有效期内就可以不用再请求新的Security Token。

因为IE低版本(IE6,7,8,9)对 HTML5 API 支持的不完善,为了在这些浏览器里面实现文件直传的功能,VOD服务中的存储服务BOS提供了PostObject接口,支持了 multipart/form-data 的请求格式,方便在低版本的IE下面把文件上传到BOS服务器。

在浏览器中直接上传文件到VOD

使用bce-bos-uploader,可以参考下面的内容完成如何在浏览器中直接上传文件到VOD。

操作流程

  1. 注册百度智能云账号,实名认证,开通VOD服务。
  2. 查询ak/sk。

    在百度智能云控制台首页右上角的“安全认证->Access Key” 查询AK和SK的信息,也可以在Bucket管理中查看。

  3. 初始化bce-bos-uploader参数。

    获取bce-bos-uploader
    通过github下载:https://github.com/baidubce/bce-bos-uploader/

  4. 修改moe/3in1.js中的:

    var AK = getQuery('ak', '替换为你的AK');
    var SK = getQuery('sk', '替换为你的SK');

    并把整个包都部署到服务器上。

  5. 启动webserver

    通过PHP来启动
    php -S 0.0.0.0:9999

  6. 通过Python来启动

    python -m SimpleHTTPServer 9999

启动webserver之后,在浏览器里面访问 http://your_server:your_port/bce-bos-uploader-gh-pages/moe/3in1.html打开刚才的页面,开始测试是否可以正常上传。

注意:

“moe/3in1.js” 是集合了百度智能云VOD、百度智能云DOC、百度智能云BOS的三合一服务。这个js的默认策略是:根据媒资后缀名的不同,自动上传至不同的服务。

  • 后缀为avi、mp4、flv、rm、rmvb、webm类型的媒资,将上传到百度智能云VOD;
  • 后缀为txt、pdf、doc、docx、ppt、pptx、xls、xlsx类型的文件,将上传到百度智能云DOC;
  • 其余类型默认上传到BOS。以3in1.js中的实际方法为准。

为了达到自动分渠道这个目标,您需要合理配置DOC和BOS相关的服务,修改moe/3in1.js中的var VOD_EXTS、var DOC_EXTS、以及function getKey(file)方法,来实现自己的业务逻辑。

举例:如果您仅开通了VOD服务,只希望用这块代码上传VOD,可以修改”3in1.js”中的function getKey(file)方法,直接return getVodKey(file);即可。

进阶篇一:STS临时认证

Bce-bos-uploader支持STS(Security Token Service)临时授权的方式。服务端生成一组具体特定操作权限、具有一定时效性的临时AK/SK,这组临时的AK/SK可以暴露给浏览器端直接使用。用户只需要将服务端返回的AK/SK及SessionToken设置为bce-bos-uploader对应的bos-ak、bos-sk和uptoken参数。

下图简单介绍了整个业务交互过程,关于STS方面的介绍请参考临时授权访问

代码实现分为应用服务器端和客户端两部分,实现过程如下:

应用服务器端Nodejs实现

配置应用服务器端,以Nodejs实现为例,服务器端会返回AK/SK/SessionToken。
配置浏览器,根据服务器端返回的AK/SK/SessionToken初始化bce-bos-uploader参数。

应用服务器端Nodejs实现:

var http = require('http');
    var url = require('url');
    var util = require('util');

    var STS = require('@baiducloud/sdk').STS;

    var kCredentials = {
        ak: '您的AK',
        sk: '您的SK'
    };

    function buildStsResponse() {
        var stsClient = new STS({
            credentials: kCredentials,
            region: 'bj'
        });
        return stsClient.getSessionToken(60 * 60 * 24, {
            accessControlList: [{
                service: 'bce:bos',
                resource: ['vod-gcqgg7xk0eqr78je/*'],
                region: '*',
                effect: 'Allow',
                permission: ['WRITE']
            }]
        }).then(function (response) {
            var body = response.body;
            return {
                AccessKeyId: body.accessKeyId,
                SecretAccessKey: body.secretAccessKey,
                SessionToken: body.sessionToken,
                Expiration: body.expiration
            };
        });
    }

    http.createServer(function (req, res) {
        console.log(req.url);

        var query = url.parse(req.url, true).query;

        var promise = null;

        if (query.sts) {
            promise = buildStsResponse();
        }

        promise.then(function (payload) {
            res.writeHead(200, {
                'Content-Type': 'text/javascript; charset=utf-8',
                'Access-Control-Allow-Origin': '*'
            });

            if (query.callback) {
                res.end(util.format('%s(%s)', query.callback, JSON.stringify(payload)));
            }
            else {
                res.end(JSON.stringify(payload));
            }
        });
    }).listen(1337);
    console.log('Server running at http://0.0.0.0:1337/');

注意:

resource: ['vod-gcqgg7xk0eqr78je/*']这一行需要自定义,具体参考STS和VOD、BOS的关系

在服务器端,用与创建bosClient实例类似的方式创建一个stsClient实例。对于stsClient实例,主要有一个方法,那就是getSessionToken。这个方法接收两个参数,第一个参数是临时授权的有效期,以秒为单位;第二个单位是具体的权限控制。

这个方法会异步访问STS授权服务器,返回一个promise对象。STS授权服务器会返回类似如下内容:

{
body: {
"accessKeyId": "d87a16e5ce1d47c1917b38ed03fbb329",
"secretAccessKey": "e9b6f59ce06c45cdaaea2296111dab46",
"sessionToken": "MjUzZjQzNTY4OTE0NDRkNjg3N2E4YzJhZTc4YmU5ZDh8AAAAABwCAAB/HfHDVV2bu5xUf6rApt2YdSLG6+21UTC62EHvIuiaamtuMQQKNkR9PU2NJGVbuWgBn8Ot0atk0HnWYQGgwgyew24HtbrX3GFiR/cDymCowm0TI6OGq7k8pGuBiCczT8qZcarH7VdZBd1lkpYaXbtP7wQJqiochDXrswrCd+J/I2CeSQT6mJiMmvupUV06R89dWBL/Vcu7JQpdYBk0d5cp2B+gdaHddBobevlBmKQw50/oOykJIuho4Wn7FgOGPMPdod0Pf0s7lW/HgSnPOjZCgRl0pihs197rP3GWpnlJRyfdCY0g0GFG6T0/FsqDbxbi8lWzF1QRTmJzzh2Tax8xoPFKGMbpntp//vGP7oPYK1JoES34TjcdcZnLzIRnVIGaZAzmZMUhPEXE5RVX1w8jPEXMJJHSrFs3lJe13o9Dwg==",
"createTime": "2016-02-16T14:01:29Z",
"expiration": "2016-02-16T15:41:29Z",
"userId": "5e433c4a8fe74765a7ec6fc147e25c80"
}
}
服务器端需要把accessKeyId、secretAccessKey、sessionToken三个字段下发给浏览器端。

配置浏览器端bce-bos-uploader参数

使用STS临时授权机制时,只需要在各个服务初始化的时候把上面所说的参数accessKeyId、secretAccessKey、sessionToken引入就可以了。对3in1.html来说,就是在服务器向客户端分发3in1.js时候,修改掉其中的

var AK = getQuery('ak', '您从STS申请到的临时AK');
var SK = getQuery('sk', '您从STS申请到的临时SK ');
var SESSION_TOKEN = '您从STS申请到的临时token';

以及对3in1.js代码中的多处
// uptoken: SESSION_TOKEN,
中的uptoken解除注释。

再次测试,在浏览器中抓包,发现authorization头中有x-bce-security-token字样,且成功,说明STS模式直传VOD测试成功。

进阶篇二:通过PostObject接口处理IE低版本

VOD服务中,上传服务是基于BOS来提供。

因为IE低版本(IE8,IE9)对html5支持的不完善,为了在这些浏览器里面实现文件直传的功能,BOS开发了PostObject接口,通过一个multipart/form-data的格式,就可以把文件上传到BOS服务器。Postobject接口的签名模式下应用服务器端对policy生成签名,再返回给客户端。

bce-bos-uploader已经实现了对这个接口的支持,使用之前需要进行额外的配置工作。

服务器端返回uptoken_url参数:
使用PostObject处理IE低版本时,需要在bce-bos-uploader中配置uptoken_url参数,关于 uptoken_url如何实现详细代码请参见uptoken代码示例。

然后修改3in1.js:

var UPTOKEN_URL = 'http://localhost.baidu.com:7788/ack';

修改为你的实际的服务器的ack接口。
再次部署和访问,就可以在IE低版本下运行3in1.html。

综上所述,用户先用真实的ak、sk在在浏览器中直接上传文件到BOS模式下开始简单测试,然后通过开发和配置“STS临时认证“的方式实现在IE高版本以及其他浏览器下的安全上传,再理解和部署ack接口,实现通过PostObject接口处理IE低版本。部署到线上正式服务的时候,3in1.js会自动根据浏览器来选择STS模式或者ack模式进行上传。