利用node 一键部署静态资源到 七牛

利用node.js 一键部署七牛

前期准备 环境配置

element

node (我的版本 v8.11.2)

npm (我的版本 v6.1.0)


npm 组件包 colors、qiniu

node 的方法 fs、path、readline、console


说明

readline 用于从可读流(如 process.stdin)读取数据,每次读取一行文档说明

colors 设置在控制台中颜色和样式风格 文档说明

fs 文件系统操作 文档说明

console 模块提供了一个简单的调试控制台,类似于 Web 浏览器提供的 JavaScript 控制台。 文档说明

path 模块提供了一些工具函数,用于处理文件与目录的路径 文档说明

qiniu 适用于Node.js的Qiniu云SDK 文档说明


除了qiniu 其他包已默认安装
执行命令
npm install qiniu

大体思路

上传
利用node的文件处理机制, 拿到指定目录下的所有文件,通过qiniuSDk一键上传到七牛云存储
批量更新
利用 qiniuSDK 获取远程指定筒和某前缀下的文件列表 批量删除后 再将本地文件全部上传

具体实现

创建 qiniu.js 文件

1.引入所需依赖

const readline  = require('readline')
const colors = require( "colors");
const FS = require('fs')
const Join = require('path').join // 路径片段连接到一起,并规范化生成的路径
const QiNiu = require('qiniu')

2.初始化配置

七牛秘钥

const accessKey = '*******'; // 七牛秘钥
const secretKey = '*******'; // 七牛秘钥
const bucket = '***' // 七牛空间名(筒名)
const prefix = '***' // 七牛目录名称(前缀)
const limit = 10 // 分页请求 每页数量
var uploadNore =  ['index.html'] // 忽略文件数组(可以为文件或文件夹)忽略文件数组(可以为文件或文件夹)

// 鉴权对象
const mac = new QiNiu.auth.digest.Mac(accessKey, secretKey);
// 获取七牛配置
const config = new QiNiu.conf.Config();
// 是否使用https域名
// config.useHttpsDomain = true;
// 上传是否使用cdn加速
// config.useCdnDomain = true;
// 空间对应的机房 Zone_z0(华东)
config.zone = QiNiu.zone.Zone_z0;
// 资源管理相关的操作首先要构建BucketManager对象
const bucketManager = new QiNiu.rs.BucketManager(mac, config);
// 相关颜色配置 console颜色主题
colors.setTheme({
  silly: 'rainbow',
  input: 'grey',
  verbose: 'cyan',
  prompt: 'grey',
  info: 'green',
  data: 'grey',
  help: 'cyan',
  warn: 'yellow',
  debug: 'blue',
  error: 'red'
});
// 

3.定义相关方法

3.1 获取远程七牛 指定空间名和前缀名的

// 这里采用异步方法操作 获取远程列表的目的只是为了删除 但只能是获取到列表后 回调里再删除
// 获取远程七牛 指定前缀 文件列表
async function getQiniuList() {
  var options = {
    limit: limit,
    prefix: prefix,
  }
  var array = []
  var list = await getList()
  // marker 上一次列举返回的位置标记,作为本次列举的起点信息
  async function getList(mark=false) {
    if(mark){
      var options = {
        limit: options.limit,
        prefix: options.prefix,
        mark: mark
      }
    }
    return new Promise(function(resolve, reject){
      bucketManager.listPrefix(bucket, options, function(err, respBody, respInfo) {
        if (err) {
          console.log(err);
          throw err;
        }
        if (respInfo.statusCode == 200) {
          //如果这个nextMarker不为空,那么还有未列举完毕的文件列表,下次调用listPrefix的时候,指定options里面的marker为这个值
          var nextMarker = respBody.marker;
          var commonPrefixes = respBody.commonPrefixes;
          var items = respBody.items;
          items.forEach(function(item) {
            array.push(QiNiu.rs.deleteOp(bucket, item.key))
          });
          if(respBody.marker){
            getList(respBody.marker)
          } else{
            resolve(array)
          }
        } else {
          console.log(respInfo.statusCode);
          console.log(respBody);
        }
      });
    })
  }
  return list
}

3.2 删除远程 七牛列表数据

// 批量删除远程七牛 指定列表 所有文件
async function delAll(){
  async function delQiniuAll() {
    return new Promise(function(resolve, reject){
      // 获取七牛远程列表数据
      getQiniuList().then(res => {
        if (res.length!==0){
          console.log('远程列表为空'.debug);
          del(res, resolve)
        } else {
          resolve()
        }
      })
    })
  }
  await delQiniuAll()
}
function del(deleteOperations, resolve) {
  bucketManager.batch(deleteOperations, function(err, respBody, respInfo) {
    if (err) {
      console.log(err);
      //throw err;
    } else {
      // 200 is success, 298 is part success
      if (parseInt(respInfo.statusCode / 100) == 2) {
        respBody.forEach(function(item, index) {
          if (item.code == 200) {
            resolve(index)
            console.log('删除成功'+'第'+(parseInt(index)+1)+'个文件'.info)
          } else {
            console.log('删除失败'.error);
            console.log(item.code + "\t" + item.data.error.error);
            resolve(index)
          }
        });
      } else {
        console.log(respInfo.deleteusCode);
        console.log(respBody);
      }
    }
  });
}

3.3 上传本地 文件到七牛

// 上传所有文件到骑牛
function upAllToQiniu(){
  console.log('开时删除七牛远程资源列表'.debug);
  // 先删除所有 再上传
  delAll().then(res => {
    console.log('开时上传资源到七牛'.debug);
    var files = FS.readdirSync('dist/'); // 文件目录
    var localFile = findSync('dist/')
    // key 为远程 七牛目录文件名
    // localFile[key] 为本地完成路径+文件名称
    for(var key in localFile){
      upOneToQiniu(localFile[key], key)
    }
  })
}

// 上传单文件到骑牛 localFile为本地完成路径+文件名称 key为远程 七牛目录文件名
function upOneToQiniu(localFile, key) {
  var mac = new QiNiu.auth.digest.Mac(accessKey, secretKey);
  var options = {
    scope: bucket,
  };
  var putPolicy = new QiNiu.rs.PutPolicy(options);
  var uploadToken = putPolicy.uploadToken(mac);
  var formUploader = new QiNiu.form_up.FormUploader(config)
  var putExtra = new QiNiu.form_up.PutExtra()
  // 文件上传
  formUploader.putFile(uploadToken, key, localFile, putExtra, function(respErr,
    respBody, respInfo) {
    if (respErr) {
      throw respErr
    }
    if (respInfo.statusCode == 200) {
      console.log(localFile.info+'=>'+respBody.key.info + '上传成功')
    } else {
      console.log('上传失败' + respInfo.statusCode.error);
      console.log('上传失败' + respBody.error)
    }
  })
}
// 拿到文件 目录路径 startPath 根目录名称
function findSync(startPath) {
  let targetObj={};
  function finder(path) {
    // 获取当前目录下的 文件或文件夹
    let files=FS.readdirSync(path);
    // 循环获 当前目录下的所有文件
    files.forEach((val,index) => {
      let fPath=Join(path,val);
      let stats=FS.statSync(fPath);
      if(stats.isDirectory()) {
        finder(fPath);
      }
      if(stats.isFile() && isNore(fPath)) {
        targetObj[fPath.replace(startPath, prefix)] = fPath;
      }
    });
  }
  finder(startPath);
  return targetObj;
}
/**
 * 判断当前路径是否在忽略文件数组中
 * @param {String} path 路径
 */
function isNore(path) {
  for( var item of uploadNore) { // 遍历忽略数组
    if (path.indexOf(item) !== -1) {
      return false
    }
  }
  return true
}

4.流程控制

// process 对象是一个全局变量,它提供当前 Node.js 进程的有关信息,以及控制当前 Node.js 进程 因为是全局变量,所以无需使用 require()。
var rl = readline.createInterface({
  input: process.stdin, // 要监听的可读流
  output: process.stdout, // 要写入逐行读取数据的可写流
  prompt: ('是否进行远程部署> (Y/N)').warn
});
rl.prompt();
// 每当 input 流接收到接收行结束符(\n、\r 或 \r\n)时触发 'line' 事件。 通常发生在用户按下 <Enter> 键或 <Return> 键。监听器函数被调用时会带上一个包含接收的那一行输入的字符串。
rl.on('line', (line) => {
  switch (line.trim()) {
    case 'y':
    case 'Y':
      console.log('开始执行远程部署'.help);
      // 上传
      upAllToQiniu()
      rl.close();
      break;
    case 'n':
    case 'N':
      console.log('您取消了远程部署'.help);
      rl.close();
      break;
    default:
      console.log(`你输入的:'${line.trim()}'为无效命令,请重新输入`.warn);
      rl.prompt();
      break;
  }
})

最后 在终端里 执行 node build/qiniu.js
或者 在 package.json scripts项 里 加入

"qiniu": "node build/qiniu.js",

然后执行 npm run qiniu 也可以

本文为作者原创,允许转载,转载后请以链接形式说明文章出处. 如转载但不标明来源,后果自负。

王浩的博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容