温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

基于服务端怎么实现OSS文件直传

发布时间:2022-06-14 09:21:52 来源:亿速云 阅读:310 作者:zzz 栏目:开发技术

这篇文章主要介绍“基于服务端怎么实现OSS文件直传”,在日常操作中,相信很多人在基于服务端怎么实现OSS文件直传问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”基于服务端怎么实现OSS文件直传”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    优缺点

    从“客户端 — 服务器 — OSS”的传输模式,变更为“客户端 — OSS”的模式,最大的好处是,省掉了上传服务器的这一步,上传效率更高,速度更快(相比较于一般服务器的带宽,可以认为 OSS 的宽带是“几乎无限”的)。

    当然该模式也有缺点,那就是增加了很多额外的开发工作量,主要包含 2 部分:

    (1)服务端增加生成上传 OSS 凭证的代码。

    (2)客户端增加从服务端获取上传 OSS 凭证的代码和对直传 OSS 进行适配。

    整体而言,直传模式除了增加一点开发工作量以外,从架构层面,几乎没有任何缺点。

    流程

    实际上,整个流程非常简单,包含了两步:

    (1)客户端向服务端发送请求,获取直传 OSS 的凭证。

    (2)客户端向 OSS 上传文件,并携带该凭证。

    逻辑拆解

    整个“生成上传 OSS 凭证”过程,实际上做了这么几件事:

    (1)上传凭证鉴权由 policy 提供,根据私密配置生成这个 policy

    (2)由于上传环节脱离了开发者服务器,因此你可以在 policy 中定义各种限制,例如上传最大体积、文件名等。

    (3)将 policy 转化为指定的格式。

    代码实现

    我们先考虑将流程的每一步实现,然后再将流程代码封装成函数。

    OSS 配置

    首先定义 OSS 的配置文件,关于配置项的内容,可以参考文档:help.aliyun.com/document_de…

    /** OSS 配置项 */
    const ossConfig = {
      bucket: 'xxxxxxxx',
      accessKeyId: 'xxxxxxxx',
      accessKeySecret: 'xxxxxxxx',
    
      /** OSS 绑定的域名 */
      url: 'xxxxxxxx',
    }

    policy 内容

    对于 policy ,有很多配置项,我们先考虑生成“写死”的模式,然后再优化为由函数参数传入配置项。以下是一个最基础的 policy

    有效期

    首先定义一个有效时长(单位:毫秒),然后该凭证的有效截止时间则为“当前时间 + 有效时长”,最后需要转化为 ISO 时间字符串格式。

    /** 有效时长:例如 4 小时 */
    const timeout = 4 * 60 * 60 * 1000
    
    /** 到期时间:当前时间 + 有效时间 */
    const expiration = new Date(Date.now() + timeout).toISOString()

    文件名

    文件名建议使用 UUID(笔者习惯性使用去掉短横线的 UUID),避免重复。

    import { v4 as uuidv4 } from 'uuid'
    
    /** 随机文件名(去掉短横线的 uuid) */
    const filename = uuidv4().replace(/-/gu, '')

    一般建议按照不同的业务模块,将文件划分不同的目录,例如这里使用 file 目录,那么完整的 OSS 文件路径则为:

    /** 目录名称 */
    const dirname = 'file'
    
    /** 文件路径 */
    const key = dirname + '/' + filename

    需要注意的是,文件路径不能以 “/” 开头(OSS 本身的要求)。

    将以上内容整合,就形成了 policy 文本,以下是一个基础格式:

    const policyText = {
      expiration: expiration,
      conditions: [
        ['eq', '$bucket', ossConfig.bucket],
        ['eq', '$key', key],
      ],
    }

    转化 policy

    policyText 转化为 Base64 格式后,就是要求的 policy 了。

    // 将 policyText 转化为 Base64 格式
    const policy = Buffer.from(JSON.stringify(policyText)).toString('base64')

    然后对 policy 使用 OSS 密钥使用 HmacSha1 算法签名签名。

    import * as crypto from 'crypto'
    
    // 使用 HmacSha1 算法签名
    const signature = crypto.createHmac('sha1', ossConfig.accessKeySecret).update(policy, 'utf8').digest('base64')

    最后将上述流程中的相关字段返回给客户端,即为“上传凭证”。

    进一步分析

    以上完整演示了整个流程,我们进一步分析,如何将其封装为一个通用性的函数。

    (1)凭证的有效时长可以根据不同的业务模块分别定义,于是做成函数配置项。

    (2)目录名称也可以做成配置项。

    (3) policy 还有更多的配置内容,可以抽取一部分做成配置项,例如“允许上传的最大体积”。

    完整代码

    以下是封装为“服务”的使用 Nest.js Web 框架的相关代码,供参考。

    import { Injectable } from '@nestjs/common'
    import * as crypto from 'crypto'
    import { v4 as uuidv4 } from 'uuid'
    
    export interface GenerateClientTokenConfig {
      /** 目录名称 */
      dirname: string
    
      /** 有效时间,单位:小时 */
      expiration?: number
    
      /** 上传最大体积,单位:MB */
      maxSize?: number
    }
    
    /** 直传凭证 */
    export interface ClientToken {
      key: string
      policy: string
      signature: string
      OSSAccessKeyId: string
      url: string
    }
    
    export interface OssConfig {
      bucket: string
      accessKeyId: string
      accessKeySecret: string
      url: string
    }
    
    @Injectable()
    export class OssService {
      private readonly ossConfig: OssConfig
    
      constructor() {
        this.ossConfig = {
          bucket: 'xxxxxxxx',
          accessKeyId: 'xxxxxxxx',
          accessKeySecret: 'xxxxxxxx',
    
          /** OSS 绑定的域名 */
          url: 'xxxxxxxx',
        }
      }
    
      /**
       * 生成一个可用于客户端直传 OSS 的调用凭证
       *
       * @param config 配置项
       *
       * @see [配置内容](https://help.aliyun.com/document_detail/31988.html#title-6w1-wj7-q4e)
       */
      generateClientToken(config: GenerateClientTokenConfig): ClientToken {
        /** 目录名称 */
        const dirname = config.dirname
    
        /** 有效时间:默认 4 小时 */
        const timeout = (config.expiration || 4) * 60 * 60 * 1000
    
        /** 上传最大体积,默认 100M */
        const maxSize = (config.maxSize || 100) * 1024 * 1024
    
        /** 随机文件名(去掉短横线的 uuid) */
        const filename = uuidv4().replace(/-/gu, '')
    
        /** 文件路径 */
        const key = dirname + '/' + filename
    
        /** 到期时间:当前时间 + 有效时间 */
        const expiration = new Date(Date.now() + timeout).toISOString()
    
        const { bucket, url, accessKeyId } = this.ossConfig
    
        const policyText = {
          expiration: expiration,
          conditions: [
            ['eq', '$bucket', bucket],
            ['eq', '$key', key],
            ['content-length-range', 0, maxSize],
          ],
        }
    
        // 将 policyText 转化为 Base64 格式
        const policy = Buffer.from(JSON.stringify(policyText)).toString('base64')
    
        // 使用 HmacSha1 算法签名
        const signature = crypto.createHmac('sha1', this.ossConfig.accessKeySecret).update(policy, 'utf8').digest('base64')
    
        return { key, policy, signature, OSSAccessKeyId: accessKeyId, url }
      }
    }

    到此,关于“基于服务端怎么实现OSS文件直传”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    oss
    AI