这篇文章主要为大家介绍了阿里云OSS实践文件直传基于服务端实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
help.aliyun.com/document_de…),但由于文档创建时间比较早,对于新手很难看懂,本文将手把手给你演示整个过程。
整个“生成上传 OSS 凭证”过程,实际上做了这么几件事:
(1)上传凭证鉴权由 policy
提供,根据私密配置生成这个 policy
。
(2)由于上传环节脱离了开发者服务器,因此你可以在 policy
中定义各种限制,例如上传最大体积、文件名等。
(3)将 policy
转化为指定的格式。
/** 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')
最后将上述流程中的相关字段返回给客户端,即为“上传凭证”。
help.aliyun.com/document_de…),可以抽取一部分做成配置项,例如“允许上传的最大体积”。
完整代码
以下是封装为“服务”的使用 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 中。
发表评论 取消回复