V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rockuw
V2EX  ›  Node.js

拥抱 ES6——OSS 推出 JavaScript SDK

  •  2
     
  •   rockuw · 2016-01-29 16:07:39 +08:00 · 5802 次点击
    这是一个创建于 3230 天前的主题,其中的信息可能已经有所发展或是发生改变。

    JavaScript 作为当下最火的语言(之一),结合 OSS 能够创建出非常丰富的跨前后端的应用。现在, OSS 正式推出 JavaScript SDK ,使用 OSS 的 前后端 同学 可以方便地使用。

    ES6

    首先,什么是 ES6 ?

    es6

    其实ES6是最新版本的 ECMAScript ,也就是 JavaScript 标准。

    ECMAScript 6, also known as ECMAScript 2015, is the latest version of the ECMAScript standard. > ES6 is a significant update to the language...

    ES6 包含了众多重要的更新,但是今天对我们最重要的就是Generator Function,因为它可以让我们用同步的方式写异步代码:

    var creds = yield  applySTSToken();
    var client = new OSS(creds);
    var result = yield client.list();
    console.log(result);
    

    上面的代码包含了两个异步的操作,applySTSTokenlist,如果没有 generator ,我们就需要在applySTSToken的 callback 中做list,然后在list的 callback 中做log,比如这样:

    applySTSToken(function (creds) {
      var client = new OSS(creds);
      client.list(function (result) {
        console.log(result);
      });
    });
    

    如果上面的代码看起来也“还可以”的话,那么当异步操作多起来之后,再考虑错误处理的场景,代码将会变得非常复杂。不得不说 callback 很锻炼大脑,但是有高科技为什么不利用呢?

    这看起来不错,但是如何实现的呢?这篇文章介绍了如何实现 Promise (这真是个好名字)。最关键的地方就是yield让控制流跳转到其他代码执行,相应的事件(callback)发生时,通过next让控制流回到上次yield的地方继续执行,这样就达到了“异步非阻塞”的效果。

    目前主流的 Chrome/Firefox 版本都已经支持 ES6 的大部分功能了。主流的 Safari 版本和移动端浏览器目前还不支持 ES6 ,但是我们后面会讲到如何做兼容性转换。

    功能

    SDK 目前支持 OSS 的绝大部分功能,包括上传 /下载文件、分片上传、 Bucket 管理、文件管理等,常用的上传 /下载也有多样的玩法:

    • 上传本地文件
    • 上传 Buffer 内容
    • 流式上传
    • 分片上传
    • 下载到本地文件
    • 流式下载

    安装

    npm install ali-oss co
    

    上传文件

    使用put接口上传一个 Object :

    var OSS = require('ali-oss');
    var co = require('co');
    var fs = require('fs');
    
    var client = new OSS({
      accessKeyId: 'access key id',
      accessKeySecret: 'access key secret',
      region: 'oss-cn-hangzhou',
      bucket: 'my-bucket',
    });
    
    co(function* () {
      // put from local file
      yield client.put('file', '/tmp/x');
    
      // put from Buffer
      yield client.put('buffer', new Buffer('hello world'));
    
      // put from Stream
      yield client.put('stream', fs.createReadStream('/tmp/x'));
    }).catch(function (err) {
      console.log(err);
    });
    

    下载文件

    使用getgetStream方法下载文件:

    co(function* () {
      // get as content
      var result = yield client.get('object');
      console.log(result.content);
    
      // download as file
      yield client.get('object', '/tmp/x');
    
      // pipe to stream
      yield client.get('object', fs.createWriteStream('/tmp/x'));
    
      // get as stream
      var result = yield client.getStream('object');
      result.stream.pipe(fs.createWriteStream('/tmp/y'));
    }).catch(function (err) {
      console.log(err);
    });
    

    管理 Bucket

    使用putBucketLifecycle等接口来设置 Bucket 的属性。注意,目前 OSS 不支持 Bucket 相关的跨域请求,所以在浏览器中不能使用 Bucket 的管理接口。

    co(function* () {
      var result = yield client.putBucketLifecycle('bucket', 'region', [
        {
          id: 'delete after one day',
          prefix: 'logs/',
          status: 'Enabled',
          days: 1
        },
        {
          prefix: 'logs2/',
          status: 'Disabled',
          date: '2022-10-11T00:00:00.000Z'
        }
      ]);
    }).catch(function (err) {
      console.log(err);
    });
    

    HTTP Headers

    SDK 的每个方法都可以设置和获取 HTTP Headers :

    co(function* () {
      // set headers
      var result = yield client.put('object', '/tmp/x', {
        headers: {
          'content-type': 'application/javascript; charset=utf8'
        }
      });
    
      // get headers
      console.log(result.res.headers);
    }).catch(function (err) {
      console.log(err);
    });
    

    前端后端

    Browserify, Babel等优秀工具的出现,使得我们能够在前后端共用一套代码。 OSS JavaScript SDK 基于 Node.js 开发,通过BrowserifyBabel产生适用于浏览器的代码,使得 OSS JavaScript SDK 同时支持在浏览器中和 Node.js 环境中使用。

    在浏览器中使用

    用户在浏览器中使用 SDK 时,首先在<head>标签中包含如下<script>标签:

    <script src="http://gosspublic.alicdn.com/aliyun-oss-sdk-4.1.4.min.js"></script>
    

    就可以在代码中使用OSS对象:

    <script type="text/javascript">
      var client = new OSS({
        region: '<oss region>',
        accessKeyId: '<Your accessKeyId(STS)>',
        accessKeySecret: '<Your accessKeySecret(STS)>',
        stsToken: '<Your securityToken(STS)>',
        bucket: '<Your bucket name>'
      });
    
      OSS.co(function* () {
        var result = yield client.list({
          'max-keys': 10
        });
        console.log(result);
      }).catch(function (err) {
        console.log(err);
      });
    </script>
    

    注意:上面的代码中用OSS.co代替co,同样的,如果用到了Buffer,也要使用OSS.Buffer代替。browser.js中显示了 SDK 暴露给浏览器的全部对象。

    我们提供一个demo,使用 OSS JavaScript SDK 开发了一个浏览器应用,提供上传文件 /上传文本 /列出文件 /下载文件 四个功能,效果如下:

    oss_in_browser_demo

    Build SDK

    只需要在 SDK 的代码目录执行npm run build-dist命令,就可以生成用于浏览器的 SDK lib :

    git clone https://github.com/ali-sdk/ali-oss.git
    cd ali-oss
    npm install
    npm run build-dist
    # output
    # dist/aliyun-oss-sdk.js
    # dist/aliyun-oss-sdk.min.js
    

    Build 用户代码

    上述的例子中使用 SDK 的代码使用了function*yield等 ES6 的特性,这在支持 ES6 的浏览器(主流版本的 Chrome/Firefox )中可以直接运行,若要用于更多的浏览器,则需要使用BrowserifyBabel进行兼容性转换:

    npm install -g browserify
    npm install babelify babel-preset-es2015
    echo '{ "presets": ["es2015"] }' > .babelrc
    browserify app.js -t babelify > app-babel.js
    

    转换后只需要在<script>标签中包含转换后的代码文件即可:

    <script src="app-babel.js"></script>
    

    发布

    在 SDK 的开发过程中,每发布一个版本,我需要手动做以下几件事情:

    • 修改 ChangeLog
    • 修改 package.json 中的版本
    • 生成版本的 tag
    • 生成 dist/aliyun-oss-sdk.min.js
    • 发布到 npm
    • aliyun-oss-sdk.min.js发布到 cdn

    这么多步骤,不出错是几乎不可能的。所以我们使用git-extrasgit-pre-hooks,让发布过程变成"All-in-One",具体参考package.json

    首先确保在 master 分支,然后 npm 依赖都安装好了:

    git checkout master
    npm install
    

    发布过程:

    vi package.json and change "version" to 4.2.0
    git changelog -n -t 4.2.0
    git release 4.2.0
    

    是不是如丝般顺滑?

    第 1 条附言  ·  2016-01-29 18:37:55 +08:00

    OSS 是阿里云的对象存储系统,提供高可用的海量存储服务。类似的产品有著名的 Amazon 的S3

    23 条回复    2016-01-30 08:07:15 +08:00
    clijiac
        1
    clijiac  
       2016-01-29 16:21:23 +08:00
    DOTA1 差评,应该放个 DOTA2 的图
    bdbai
        2
    bdbai  
       2016-01-29 16:31:10 +08:00 via iPhone
    没有用过阿里云 OSS ,但是把 ak 、 sk 都放前端真的好吗?
    rockuw
        3
    rockuw  
    OP
       2016-01-29 16:35:15 +08:00   ❤️ 1
    @bdbai 前端使用的 AK 、 SK 是从应用服务器获取的临时密钥,请参考[阿里云 STS]( https://help.aliyun.com/document_detail/oss/practice/ram_guide/overview.html)。
    rockuw
        4
    rockuw  
    OP
       2016-01-29 16:36:06 +08:00
    @clijiac 喜欢 dota1 的画风
    wbsdty331
        5
    wbsdty331  
       2016-01-29 16:36:36 +08:00
    先大再跳
    libook
        6
    libook  
       2016-01-29 16:50:54 +08:00
    题主写的不错,支持一个。

    学 ES6,我看的是这个 http://es6.ruanyifeng.com/ 讲得很好。
    用 Koa 做 API 的话自带深度 co , Mongoose 等包自带 Promise ,没有 Promise 的话 ES6 也原生支持 Promise 了,只需要 new Promise(function(resolve,reject){/* Code */})
    sox
        7
    sox  
       2016-01-29 16:53:23 +08:00   ❤️ 2
    @libook 再推荐一个更深度的 ES6 教程 http://exploringjs.com/es6
    rockuw
        8
    rockuw  
    OP
       2016-01-29 17:07:18 +08:00
    @libook 阮老师写得确实不错
    nakupanda
        9
    nakupanda  
       2016-01-29 17:41:02 +08:00
    旱地神牛 6
    magicdawn
        10
    magicdawn  
       2016-01-29 18:11:24 +08:00
    嗯, 我觉得应该定下标准吧... 例如函数名, 怎么区分 callback 版 & Promise 版...
    我觉得 bluebird 的 promisify 的 xxx 与 xxxAsync 非常不错, 值得实践...
    magicdawn
        11
    magicdawn  
       2016-01-29 18:12:56 +08:00
    @sox 看起来不错的样子... v8 4.9 就要带来 90%+ ES6 feature 了... 收藏备用 ...
    yurivvvvv
        12
    yurivvvvv  
       2016-01-29 18:26:59 +08:00
    @wbsdty331 团战已输
    rannnn
        13
    rannnn  
       2016-01-29 18:29:09 +08:00   ❤️ 1
    说了半天不知道 OSS 是什么东西
    FrankFang128
        14
    FrankFang128  
       2016-01-29 18:36:15 +08:00 via Android
    已经 7 了
    rockuw
        15
    rockuw  
    OP
       2016-01-29 18:38:23 +08:00
    @rannnn my bad. 已更新
    rockuw
        16
    rockuw  
    OP
       2016-01-29 18:39:20 +08:00
    @FrankFang128 7 还没有发布哦
    rockuw
        17
    rockuw  
    OP
       2016-01-29 18:40:09 +08:00
    Tankpt
        18
    Tankpt  
       2016-01-29 19:03:04 +08:00
    用过。。挺不错的。
    LukeXuan
        19
    LukeXuan  
       2016-01-29 19:54:05 +08:00
    ES6 大跳
    CheungKe
        20
    CheungKe  
       2016-01-29 20:03:12 +08:00
    被图吸引了,看了半天,标题当
    hantsy
        21
    hantsy  
       2016-01-29 21:15:34 +08:00
    cool work
    chemzqm
        22
    chemzqm  
       2016-01-30 07:58:06 +08:00
    require('babel-polyfill');
    既然用了这个东西,能不能写到文档里?不然用户可能在页面上重复引用的,这玩意蛮大的
    rockuw
        23
    rockuw  
    OP
       2016-01-30 08:07:15 +08:00 via iPhone
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3550 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 05:00 · PVG 13:00 · LAX 21:00 · JFK 00:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.