Node.js操作七牛云OSS进行多文件压缩为zip的方法

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: Node.js操作七牛云OSS进行多文件压缩为zip的方法

前言


最近在用七牛云对象存储服务做了一个小应用


需要用到批量下载文件的操作,qiniu-OSS-SDK只直接提供了单个文件的下载方法,批量下载得自己组装


这里批量下载的实现逻辑如下:

  1. 对要下载的资源归档到一个ZIP压缩包里
  2. 下载这个压缩包


不得不吐槽,这部分的文档对新手很不友好,直接看蒙

下面展开介绍


准备工作


项目中安装qiniu依赖


npm i qiniu


鉴权代码,通过accessKeysecretKey鉴权


const qiniu = require('qiniu')
const qiniuConfig = {
    accessKey: process.env.qiniu_accessKey,
    secretKey: process.env.qiniu_secretKey
}
const mac = new qiniu.auth.digest.Mac(qiniuConfig.accessKey, qiniuConfig.secretKey)


公共参数


// 空间名称
const bucket = 'bucket'
// 空间绑定的域名
const privateBucketDomain = 'http://example.com'


依赖方法汇总


上传凭证获取


凭证默认1小时有效,客户端需要此凭证进行上传鉴权


function getUploadToken(): string {
  const putPolicy = new qiniu.rs.PutPolicy({
    scope: bucket,
    // expires: 3600,
    // returnBody: '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'
  })
  return putPolicy.uploadToken(mac)
}


通过returnBody可以自定义上传成功的响应参数


获取OSS文件的下载链接


const getDeadline = () => {
    // 12小时过期
    return Math.floor(Date.now() / 1000) + 3600 * 12
}
/**
 * 获取OSS上文件的下载链接
 * @param key 文件的key
 * @param expiredTime 链接过期的具体时间
 */
function createDownloadUrl(key, expiredTime = getDeadline()) {
    const config = new qiniu.conf.Config()
    const bucketManager = new qiniu.rs.BucketManager(mac, config)
    return bucketManager.privateDownloadUrl(privateBucketDomain, key, expiredTime)
}


多个资源归档为压缩包


这个地方文档非常模糊,需要耗费不少时间试错,需要用到前面提到的:

  • 获取资源下载链接方法
  • 获取资源上传凭证方法


资源归档方法


const path = require('path')
const qiniu = require('qiniu')
const { urlsafeBase64Encode } = qiniu.util
function getKeyInfo(key: string) {
  const { name, base, ext } = path.parse(key)
  return {
    name, base, ext,
  }
}
/**
 * 资源归档为zip
 * @param {string[]} keys 需要归档的资源
 * @param {string} zipName 压缩包名称 
 * @returns 
 */
function makeZipWithKeys(keys, zipName){
  return new Promise((res) => {
    const names = []
    const content = keys.map((key) => {
      // 拼接原始url
      // 链接加密并进行Base64编码,别名去除前缀目录。
      const keyInfo = getKeyInfo(key)
      const { name, ext } = keyInfo
      let { base } = keyInfo
      // 判断别名是否存在,存在则后缀+数字自增
      let i = 1
      while (names.includes(base)) {
        base = `${name}_${i}${ext}`
        i += 1
      }
      names.push(base)
      const safeUrl = `/url/${urlsafeBase64Encode(createDownloadUrl(key))}/alias/${urlsafeBase64Encode(base)}`
      return safeUrl
    }).join('\n')
    const config = new qiniu.conf.Config({ zone: qiniu.zone.Zone_z2 })
    const formUploader = new qiniu.form_up.FormUploader(config)
    const putExtra = new qiniu.form_up.PutExtra()
    const key = `${Date.now()}-${~~(Math.random() * 1000)}.txt`
    formUploader.put(getUploadToken(), key, content, putExtra, (respErr,
      respBody, respInfo) => {
      if (respErr) {
        throw respErr
      }
      if (respInfo.statusCode == 200) {
        const { key } = respBody
        // 执行压缩 ,设置压缩资源的在OSS上的保存路径
        const zipKey = urlsafeBase64Encode(`${bucket}:temp_package/${Date.now()}/${zipName}.zip`)
        const fops = `mkzip/4/encoding/${urlsafeBase64Encode('gbk')}|saveas/${zipKey}`
        const operManager = new qiniu.fop.OperationManager(mac, config)
        const pipeline = '' // 使用公共队列
        // 下行。不知用处
        const options = { force: false }
        operManager.pfop(bucket, key, [fops], pipeline, options, (err, respBody, respInfo) => {
          if (err) {
            throw err
          }
          if (respInfo.statusCode == 200) {
            // 可直接通过statusUrl查询处理状态
            const statusUrl = `http://api.qiniu.com/status/get/prefop?id=${respBody.persistentId}`
            console.log(statusUrl)
            // 这里只返回任务id,转由客户端发请求查询
            res(respBody.persistentId)
          } else {
            console.log(respInfo.statusCode)
            console.log(respBody)
          }
        })
      } else {
        console.log(respInfo.statusCode)
        console.log(respBody)
      }
    })
  })
}


查看资源归档完成状态


/**
 * 查询Fop任务完成状态
 * @param {string} persistentId 
 * @returns 
 */
function checkFopTaskStatus(persistentId){
  const config = new qiniu.conf.Config()
  const operManager = new qiniu.fop.OperationManager(null, config)
  return new Promise((res) => {
    operManager.prefop(persistentId, (err, respBody, respInfo) => {
      if (err) {
        console.log(err)
        throw err
      }
      if (respInfo.statusCode == 200) {
        // 结构 ![图片](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/011f49a2692343aba42dc182895b86d7~tplv-k3u1fbpfcp-zoom-1.image)
        const item = respBody.items[0]
        const { code, key } = item
        res({ code, key })
      } else {
        console.log(respInfo.statusCode)
        console.log(respBody)
      }
    })
  })
}


响应的 respBody 如图


网络异常,图片无法展示
|


归档完成后即可调用下载资源文件的方法,下载归档的文件


参考


相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
15天前
|
JavaScript
js两种移除事件的方法
js两种移除事件的方法
29 2
|
15天前
|
JavaScript 前端开发
JS几种拼接字符串的方法
JS几种拼接字符串的方法
39 1
|
3天前
|
人工智能 JavaScript 网络安全
ToB项目身份认证AD集成(三完):利用ldap.js实现与windows AD对接实现用户搜索、认证、密码修改等功能 - 以及针对中文转义问题的补丁方法
本文详细介绍了如何使用 `ldapjs` 库在 Node.js 中实现与 Windows AD 的交互,包括用户搜索、身份验证、密码修改和重置等功能。通过创建 `LdapService` 类,提供了与 AD 服务器通信的完整解决方案,同时解决了中文字段在 LDAP 操作中被转义的问题。
|
4天前
|
存储 JavaScript 前端开发
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
JavaScript 数据类型分为基本数据类型和引用数据类型。基本数据类型(如 string、number 等)具有不可变性,按值访问,存储在栈内存中。引用数据类型(如 Object、Array 等)存储在堆内存中,按引用访问,值是可变的。本文深入探讨了这两种数据类型的特性、存储方式、以及检测数据类型的两种常用方法——typeof 和 instanceof,帮助开发者更好地理解 JavaScript 内存模型和类型检测机制。
10 0
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
|
9天前
|
JavaScript 前端开发 测试技术
JS都有哪些操作数组的方法
JS都有哪些操作数组的方法
15 3
|
9天前
|
缓存 JavaScript 前端开发
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
20 1
|
10天前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
11 2
|
4天前
|
存储 JavaScript 前端开发
JavaScript数组去重的八种方法详解及性能对比
在JavaScript开发中,数组去重是一个常见的操作。本文详细介绍了八种实现数组去重的方法,从基础的双重循环和 indexOf() 方法,到较为高级的 Set 和 Map 实现。同时,分析了每种方法的原理和适用场景,并指出了使用 Set 和 Map 是目前最优的解决方案。通过本文,读者可以深入理解每种方法的优缺点,并选择最合适的数组去重方式。
10 0
|
5天前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
38 0
|
5天前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
14 0