阿里云OSS文件上传(分片上传、断点续传)前后端实现

本文详细介绍了如何使用阿里云OSS服务进行前端文件上传,包括后端通过RAM和STS为前端提供临时授权,前端使用aliyun-oss SDK进行文件上传,以及断点续传、进度显示等功能的实现。涉及到的关键步骤包括创建Bucket、配置跨域、创建RAM用户和角色、生成和使用STSToken等。
摘要由CSDN通过智能技术生成

转载地址:https://segmentfault.com/a/1190000020963346        

 

关于阿里云 OSS 的介绍请参考官方文档:阿里云 OSS

出于账号安全的考虑,前端使用 OSS 服务需要走临时授权,即拿一个临时凭证(STS Token)去调用 aliyun-oss SDK。关于临时授权请参考:RAM 和 STS 介绍RAM 子账号STS 临时授权访问 OSS

以 NodeJs 为例,后端给前端颁发临时凭证的实现可参考:Node STS 授权访问

前端上传文件到阿里云的相关操作可参考:浏览器端上传文件

了解以上概念之后,接下来可以去阿里云 OSS 的控制台进行相关的设置了(前提是开通了 OSS 服务)。

阿里云 OSS 控制台配置

1. 创建 Bucket

首先,我们创建一个 bucket,一个存储文件的容器:

接着,我们需要给 bucket 设置跨域,这样我们才能在网页中调用 Aliyun OSS 服务器的接口:

2. 创建 RAM 用户

接下来,前往 RAM 控制台进行子账号和权限的配置。

首先,我们创建一个用户,并给该用户分配调用 STS 服务 AssumeRole 接口的权限,这样待会儿后端就能以该用户的身份给前端分配 STS 凭证了:

我们需要保存一下该用户的 access key 和 access key secret,后端需要以此核实用户的身份。

3. 创建 RAM 角色

该角色即有权限在前端调用 aliyun-oss SDK 上传文件的用户角色,例如我们创建一个只有上传权限的角色,命名为 uploader:

接下来我们需要给该角色分配权限,可以通过创建一条权限策略并分配给角色,该权限策略里面只包含了上传文件、分片上传相关的权限:

策略具体内容为:

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "oss:PutObject",
        "oss:InitiateMultipartUpload",
        "oss:UploadPart",
        "oss:UploadPartCopy",
        "oss:CompleteMultipartUpload",
        "oss:AbortMultipartUpload",
        "oss:ListMultipartUploads",
        "oss:ListParts"
      ],
      "Resource": [
        "acs:oss:*:*:mudontire-test",
        "acs:oss:*:*:mudontire-test/*"
      ]
    }
  ]
}

然后,把该策略赋予 uploader 角色:

到此,阿里云 OSS 后台相关配置结束。接下来,我们来关注前后端的实现。

后端实现

由于是前端负责上传,所以后端的任务比较简单,就是提供一个 STS Token 给前端。本文以 NodeJs 为例实现如下。

1. 安装 aliyun-oss SDK

npm install ali-oss

2. 生成 STS Token 并返回

const OSS = require('ali-oss');
const STS = OSS.STS;

const sts = new STS({
  accessKeyId: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY,
  accessKeySecret: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY_SECRET
});

async function getCredential(req, res, next) {
  try {
    const { credentials } = await sts.assumeRole(
      'acs:ram::1582938330607257:role/uploader',  // role arn
      null, // policy
      15 * 60, // expiration
      'web-client' // session name
    );
    req.result = credentials;
    next();
  } catch (err) {
    next(err);
  }
}

其中,access key 和 access key secret 保存在.env文件中。sts.assumeRole()返回的即为 STS Token,方法接收的四个参数分别为:role arnpolicyexpirationsession name

Role arn 可以从 RAM 角色的详情页面获取:

Policy 是自定义的策略,由于已经为角色添加了权限策略,所以可以传null

Expiration 是 STS Token 的过期时间,应该在 15min ~ 60min 之间。当 Token 失效时前端需要重新获取。

Session name 为自定义的一个会话名称。

后端实现完成!

前端实现

<!-- 本文的前端实现基于 React + Ant design pro。最终效果如下:

针对 Andt 的 Upload控件进行了简单的封装,当添加文件的时候不会立即上传,而要等到点击“提交”按钮时再上传。 -->

本文前端实现使用原生 JS,另外还有 ant design pro 的版本请参考 github 项目。

前端实现有几个关键点:

  1. 调用 aliyun-oss SDK 之前获取 STS Token
  2. 定义上传分片大小,如果文件小于分片大小则使用普通上传,否则使用分片上传
  3. 上传过程中能展示上传进度
  4. 上传过程中,如果 STS Token 快过期了,则先暂停上传重新获取 Token,接着进行断点续传
  5. 支持手动暂停、续传功能
  6. 上传完成后返回文件对应的下载地址

1. 引入 aliyun-oss SDK

参考 引入 aliyun-oss SDK

2. HTML

HTML 中包含文件选择器,上传、暂停、续传按钮,状态显示:

<div>
  <input type="file" id='fileInput' multiple='true'>
  <button id="uploadBtn" οnclick="upload()">Upload</button>
  <button id="stopBtn" οnclick="stop()">Stop</button>
  <button id="resumeBtn" οnclick="resume()">resume</button>
  <h2 id='status'></h2>
</div>

3. 定义变量

let credentials = null; // STS凭证
let ossClient = null; // oss客户端实例
const fileInput = document.getElementById('fileInput'); // 文件选择器
const status = document.getElementById('status'); // 状态显示元素
const bucket = 'mudontire-test'; // bucket名称
const region = 'oss-cn-shanghai'; // oss服务区域名称
const partSize = 1024 * 1024; // 每个分片大小(byte)
const parallel = 3; // 同时上传的分片数
const checkpoints = {}; // 所有分片上传文件的检查点

4. 获取 STS 凭证,创建 OSS Client

// 获取STS Token
function getCredential() {
  return fetch('http://localhost:5050/api/upload/credential')
    .then(res => {
      return res.json()
    })
    .then(res => {
      credentials = res.result;
    })
    .catch(err => {
      console.error(err);
    });
}

// 创建OSS Client
async function initOSSClient() {
  const { AccessKeyId, AccessKeySecret, SecurityToken } = credentials;
  ossClient = new OSS({
    accessKeyId: AccessKeyId,
    accessKeySecret: AccessKeySecret,
    stsToken: SecurityToken,
    bucket,
    region
  });
}

5. 点击上传按钮事件

async function upload() {
  status.innerText = 'Uploading';
  // 获取STS Token
  await getCredential();
  const { files } = fileInput;
  const fileList = Array.from(files);
  const uploadTasks = fileList.forEach(file => {
    // 如果文件大学小于分片大小,使用普通上传,否则使用分片上传
    if (file.size < partSize) {
      commonUpload(file);
    } else {
      multipartUpload(file);
    }
  });
}

6. 普通上传

// 普通上传
async function commonUpload(file) {
  if (!ossClient) {
    await initOSSClient();
  }
  const fileName = file.name;
  return ossClient.put(fileName, file).then(result => {
    console.log(`Common upload ${file.name} succeeded, result === `, result)
  }).catch(err => {
    console.log(`Common upload ${file.name} failed === `, err);
  });
}

7. 分片上传

// 分片上传
async function multipartUpload(file) {
  if (!ossClient) {
    await initOSSClient();
  }
  const fileName = file.name;
  return ossClient.multipartUpload(fileName, file, {
    parallel,
    partSize,
    progress: onMultipartUploadProgress
  }).then(result => {
    // 生成文件下载地址
    const url = `http://${bucket}.${region}.aliyuncs.com/${fileName}`;
    console.log(`Multipart upload ${file.name} succeeded, url === `, url)
  }).catch(err => {
    console.log(`Multipart upload ${file.name} failed === `, err);
  });
}

9. 断点续传

// 断点续传
async function resumeMultipartUpload() {
  Object.values(checkpoints).forEach((checkpoint) => {
    const { uploadId, file, name } = checkpoint;
    ossClient.multipartUpload(uploadId, file, {
      parallel,
      partSize,
      progress: onMultipartUploadProgress,
      checkpoint
    }).then(result => {
      console.log('before delete checkpoints === ', checkpoints);
      delete checkpoints[checkpoint.uploadId];
      console.log('after delete checkpoints === ', checkpoints);
      const url = `http://${bucket}.${region}.aliyuncs.com/${name}`;
      console.log(`Resume multipart upload ${file.name} succeeded, url === `, url)
    }).catch(err => {
      console.log('Resume multipart upload failed === ', err);
    });
  });
}

10. 分片上传进度

在 progress 回调中我们可以判断 STS Token 是否快过期了,如果快过期了则先取消上传获取新 Token 后在从之前的断点开始续传。

// 分片上传进度改变回调
async function onMultipartUploadProgress(progress, checkpoint) {
  console.log(`${checkpoint.file.name} 上传进度 ${progress}`);
  checkpoints[checkpoint.uploadId] = checkpoint;
  // 判断STS Token是否将要过期,过期则重新获取
  const { Expiration } = credentials;
  const timegap = 1;
  if (Expiration && moment(Expiration).subtract(timegap, 'minute').isBefore(moment())) {
    console.log(`STS token will expire in ${timegap} minutes,uploading will pause and resume after getting new STS token`);
    if (ossClient) {
      ossClient.cancel();
    }
    await getCredential();
    await resumeMultipartUpload();
  }
}

11. 暂停、续传按钮点击事件

// 暂停上传
function stop() {
  status.innerText = 'Stopping';
  if (ossClient) ossClient.cancel();
}

// 续传
function resume() {
  status.innerText = 'Resuming';
  if (ossClient) resumeMultipartUpload();
}

github 示例项目

项目地址:https://github.com/MudOnTire/...。如果对大家有帮助,star一下吧。

实现Vue阿里云OSS断点续传,可以按照以下步骤进行操作: 1. 首先,安装ali-oss依赖库,可以使用npm命令进行安装:npm install ali-oss --save。 2. 创建一个RAM用户,分配相应的角色和权限策略,确保该用户拥有上传文件到OSS的权限。 3. 在Vue项目中引入OSS对象,并声明一个全局变量ossClient和tempCheckpoint。可以在项目的入口文件或者所需要使用的组件中引入OSS对象。例如,使用require语句引入OSS对象:const OSS = require('ali-oss')。 4. 初始化ossClient和tempCheckpoint变量,ossClient用于连接到阿里云OSS服务,tempCheckpoint用于记录已完成上传分片及其对应的etag值。 5. 在文件上传时,根据需要将文件切分成多个分片,并使用ossClient.uploadPart方法进行分片上传。在每次分片上传完成后,更新tempCheckpoint数组。 6. 如果上传过程中中断了,可以通过tempCheckpoint数组来恢复上次上传的进度。重新初始化ossClient,并使用ossClient.uploadPart方法继续上传剩余的分片。 通过以上步骤,就可以实现Vue阿里云OSS断点续传功能。这样即使在上传大文件的过程中出现中断,也可以从上次中断的地方继续上传,提高文件上传的可靠性和效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [阿里云oss文件分片断点续传上传](https://blog.csdn.net/m0_49106791/article/details/119766365)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值