前言

在日常开发中,客户端上传文件的一般流程是:客户端向服务端发送文件,再由服务端将文件转储到专门的存储服务器或云计算厂商的储存服务(例如阿里云 OSS)上,这样做的一个弊端是上传环节占用服务器的带宽,个位数的并发上传就能把带宽占满,从而导致用户体验下降。而如果直接将文件从客户端直传到第三方的存储服务上,就可以避免这个问题。

本文以阿里云 OSS(Object Storage Service,对象存储服务)为例,详细说明将文件从客户端直传 OSS 的整体流程,并提供了完整的代码演示。

优缺点

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

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

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

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

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

流程

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

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

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

逻辑拆解

关于如何生成凭证(也叫签名),可以阅读官方文档(help.aliyun.com/document_de…),但由于文档创建时间比较早,对于新手很难看懂,本文将手把手给你演示整个过程。 ​

整个“生成上传 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 还有更多的配置内容(见文档 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 中。 ​

以上就是阿里云OSS实践文件直传基于服务端的详细内容,更多关于OSS文件直传服务端的资料请关注Devmax其它相关文章!

阿里云OSS实践文件直传基于服务端的更多相关文章

  1. React服务端渲染和同构的实现

    本文主要介绍了React服务端渲染和同构的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. ThinkPHP 3使用OSS的方法

    这篇文章主要介绍了ThinkPHP 3使用OSS的方法,非常不错,具有一定的参考借鉴借鉴,需要的朋友可以参考下

  3. 服务端nodejs抓取jsonp接口数据实现示例

    这篇文章主要为大家介绍了服务端nodejs抓取jsonp接口数据实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. Thinkphp整合阿里云OSS图片上传实例代码

    kphp3.2整合阿里云OSS图片上传实例,图片上传至OSS可减少服务器压力,节省宽带,安全又稳定,阿里云OSS对于做负载均衡非常方便,不用传到各个服务器了,本文通过实例代码给大家介绍,需要的朋友一起看看吧

  5. yii2.0整合阿里云oss的示例代码

    本篇文章主要介绍了yii2.0整合阿里云oss的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. 阿里对象存储OSS在laravel框架中的使用方法

    今天小编就为大家分享一篇阿里对象存储OSS在laravel框架中的使用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  7. laravel 实现阿里云oss文件上传功能的示例

    这篇文章主要介绍了laravel 实现阿里云oss文件上传功能,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  8. Python基于socket实现TCP客户端和服务端

    这篇文章主要介绍了Python基于socket实现的TCP客户端和服务端,以及socket实现的多任务版TCP服务端,下面相关操作需要的小伙伴可以参考一下

  9. 详解Angular5 服务端渲染实战

    本篇文章主要介绍了详解Angular5 服务端渲染实战,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. python利用socket实现客户端和服务端之间进行通信

    这篇文章主要介绍了python实现客户端和服务端之间进行通信,文章通过python利用socket展开详情介绍,具有一定的参考价值,需要的小伙伴可以参考一下

随机推荐

  1. Error: Cannot find module ‘node:util‘问题解决

    控制台 安装 Vue-Cli 最后一步出现 Error: Cannot find module 'node:util' 问题解决方案1.问题C:\Windows\System32>cnpm install -g @vue/cli@4.0.3internal/modules/cjs/loader.js:638 throw err; &nbs

  2. yarn的安装和使用(全网最详细)

    一、yarn的简介:Yarn是facebook发布的一款取代npm的包管理工具。二、yarn的特点:速度超快。Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。超级安全。在执行代码之前,Yarn 会通过算法校验每个安装包的完整性。超级可靠。使用详细、简洁的锁文件格式和明确的安装算法,Yarn 能够保证在不同系统上无差异的工作。三、y

  3. 前端环境 本机可切换node多版本 问题源头是node使用的高版本

    前言投降投降 重头再来 重装环境 也就分分钟的事 偏要折腾 这下好了1天了 还没折腾出来问题的源头是node 使用的高版本 方案那就用 本机可切换多版本最终问题是因为nodejs的版本太高,导致的node-sass不兼容问题,我的node是v16.14.0的版本,项目中用了"node-sass": "^4.7.2"版本,无法匹配当前的node版本根据文章的提

  4. nodejs模块学习之connect解析

    这篇文章主要介绍了nodejs模块学习之connect解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  6. 详解koa2学习中使用 async 、await、promise解决异步的问题

    这篇文章主要介绍了详解koa2学习中使用 async 、await、promise解决异步的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. Node.js编写爬虫的基本思路及抓取百度图片的实例分享

    这篇文章主要介绍了Node.js编写爬虫的基本思路及抓取百度图片的实例分享,其中作者提到了需要特别注意GBK转码的转码问题,需要的朋友可以参考下

  8. CentOS 8.2服务器上安装最新版Node.js的方法

    这篇文章主要介绍了CentOS 8.2服务器上安装最新版Node.js的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. node.js三个步骤实现一个服务器及Express包使用

    这篇文章主要介绍了node.js三个步骤实现一个服务器及Express包使用,文章通过新建一个文件展开全文内容,具有一定的参考价值,需要的小伙伴可以参考一下

  10. node下使用UglifyJS压缩合并JS文件的方法

    下面小编就为大家分享一篇node下使用UglifyJS压缩合并JS文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

返回
顶部