当前位置: 首页 > news >正文

javaScript实现客户端直连AWS S3(亚马逊云)文件上传、断点续传、断网重传

写在前面:在做这个调研时我遇到的需求是前端直接对接亚马逊平台实现文件上传功能。上传视频文件通常十几个G、客户工作环境网络较差KB/s,且保证上传是稳定的,支持网络异常断点重试、文件断开支持二次拖入自动重传等。综合考虑使用的Aws S3的分段上传功能,基于分段的特性在应用层面上实现断点、断网重传功能。

 本文主要参考亚马逊中文博客:

客户端直连S3实现断点续传思路与实践

AWS api英文官方文档

Class: AWS.S3 — AWS SDK for JavaScript

安装aws-sdk

 首先npm安装aws-sdk

npm i aws-sdk

引入aws-sdk

使用的时候通过import aws from "aws-sdk"全局导入

import aws from "aws-sdk";

配置aws秘钥信息

  const secret = await getSecret();//调用后端api获取上传配置信息//对接asw需要的配置信息const config = {accessKeyId: secret.ak,secretAccessKey: secret.sk,region: secret.regions,};//配置秘钥信息aws.config.update(config);const awsClient = new aws.S3();

上传秘钥、桶、对象key的作用

      Bucket: 后端给的,相当于文件夹名称,

      Key: 通常是上传文件的name,file.name,

      Body: 文件本身,file

分片/分段上传模式

使用createMultipartUpload方法创建一个多段上传任务,并使用uploadPart方法上传单个分片。所有分片上传后手动调completeMultipartUpload方法校验上传任务是否全部完成。

createMultipartUpload创建分段上传任务该方法返回本次上传ID,示例

//初始化分片上传
async function initMultiPartUpload(awsClient: any, params: any) {const result = await awsClient.createMultipartUpload(params).promise();return result.UploadId;
}

在调用uplodPart方法前需要手动对文件进行切片,示例

const PartSize = 10 * 1024 * 1024; // 10 MBasync function awsUploadPart(fileState: FileState,file: File,uploadId: string,key: string,awsClient: any
) {const count = Math.ceil(file.size / PartSize);const uploadPromises = [];for (let n = 1; n <= count; n++) {const start = (n - 1) * PartSize;const end = Math.min(start + PartSize, file.size) - 1;if (!partNumbers.includes(n)) {const uploadPromise = awsClient.uploadPart({Bucket,Key: key,UploadId: uploadId,PartNumber: n,Body: file.slice(start, end + 1),}).promise().then((data: any) => {completeParts.push({ PartNumber: n, ETag: data.ETag });fileState.percent = parseInt((completeParts.length * 100) / count);}).catch((err: any) => {fileState.status = FileStatus.fail;throw err;});uploadPromises.push(uploadPromise);}}//所有分片上传完成后手动合并Promise.all(uploadPromises).then(() => {checkMultiPart(uploadId, completeParts, fileState, key, awsClient);}).catch(() => {fileState.status = FileStatus.fail;});
}

分片上传完成校验

由于promise异步执行,分片派发的顺序和完成的顺序可能不一致,而completeMultipartUpload方法接收的已上传分片信息的PartNumber必须是按序排列的,因此用排序好的newParts

//aws合并分片校验
function completeMultiUpload(uploadId: any,parts: any,fileState: FileState,key: any,awsClient: any,sk: any
) {//分片信息按PartNumber顺序排序const newParts = parts.sort((a: any, b: any) => a.PartNumber - b.PartNumber);awsClient.completeMultipartUpload({Bucket: sk.bucketName,UploadId: uploadId,MultipartUpload: {Parts: newParts,},Key: key,}).promise().then(() => {fileState.status = FileStatus.success;fileState.percent = 100;}).catch(() => {fileState.status = FileStatus.fail;});
}

断点重传、二次拖入续传

Aws s3不支持断点续传。需要在应用层面进行相应的处理来实现这个功能。在上传开始时,根据文件名,key值,手动调aws获取历史上传分片信息,使用listMultipartUploads和listParts方法获取已上传的部分,并使用分段上传方法继续上传剩余的部分。

//获取当前文件是否有已上传断点信息
async function getAwsCheckpoint(key: string,awsClient: any,sk: any
): Promise<any> {let uploadId = "";let partsInfo;try {const result = await awsClient.listMultipartUploads({Bucket: sk.bucketName,Prefix: key,}).promise();if (result.Uploads.length) {uploadId = result.Uploads[result.Uploads.length - 1].UploadId; //获取具体分片信息partsInfo = await awsClient.listParts({Bucket: sk.bucketName,Key: key,UploadId: uploadId,}).promise();}} catch (err: any) {console.log(err);}return { uploadId, partsInfo };
}

思考:如果文件已经全部上传是不是不用调listMultipartUploads和listParts获取分片上传的信息了?

使用aws提供的headObject方法,先校验文件是否上传,未上传headObject方法会抛出错误;反之文件已传完。这里的逻辑是文件上传完成后在桶Bucket文件夹下会显示文件,未上传或缺失上传分片的将找不到。

因此整个逻辑梳理如下:

headObject判断文件是否已存在,已存在,上传进度100%

文件部分上传--》过滤出已上传的分片,这里同个文件多次上传取最近一次的上传记录。将未上传的分片信息上传

从未上传--》初始化分片信息--》分段上传

async function awsRequest(fileState: FileState,file: any,key: string,
) {const secret = await getSecret();const config = {accessKeyId: secret.ak,secretAccessKey: secret.sk,region: secret.regions,};//配置秘钥信息aws.config.update(config);const awsClient = new aws.S3();const params = {Bucket: secret.bucketName,Key: key,}; try {//检查文件是否已上传awsClient.headObject(params, async (err: any, data: any) => {// 没有上传成功,head方法会返回失败if (err) {//检查是否部分上传const { uploadId, partsInfo } = await getAwsCheckpoint(key,awsClient,secret);if (uploadId) {//断点续传awsUploadPart(fileState,file,uploadId,partsInfo.Parts,key,awsClient,secret);} else {//初始化文件上传const uploadId = await initMultiPartUpload(awsClient, params);awsUploadPart(fileState,file,uploadId,[],key,awsClient,secret);}} else {//data存在,上传成功fileState.percent = 100;fileState.status = FileStatus.success;}});} catch (err: any) {console.log(err);}
}

 扩展分段上传方法:传入已上传的分片信息

async function awsUploadPart(fileState: FileState,file: File,uploadId: string,parts: any,key: string,awsClient: any
) {//已完成的分片const completeParts = parts.map((_: any) => {return { PartNumber: _.PartNumber, ETag: _.ETag };});const count = Math.ceil(file.size / PartSize);const partNumbers = parts.map((_: any) => _.PartNumber);if (partNumbers.length) {fileState.status = FileStatus.processing;fileState.percent = parseInt((completeParts.length * 100) / count);}const uploadPromises = [];for (let n = 1; n <= count; n++) {if (!startTime) {startTime = new Date();}const start = (n - 1) * PartSize;const end = Math.min(start + PartSize, file.size) - 1;if (!partNumbers.includes(n)) {const uploadPromise = awsClient.uploadPart({Bucket,Key: key,UploadId: uploadId,PartNumber: n,Body: file.slice(start, end + 1),}).promise().then((data: any) => {completeParts.push({ PartNumber: n, ETag: data.ETag });fileState.percent = parseInt((completeParts.length * 100) / count);}).catch((err: any) => {fileState.status = FileStatus.fail;throw err;});uploadPromises.push(uploadPromise);}}//所有分片上传完成后手动合并Promise.all(uploadPromises).then(() => {checkMultiPart(uploadId, completeParts, fileState, key, awsClient);}).catch(() => {fileState.status = FileStatus.fail;});
}

awsRequest方法对文件做了断点续传处理,如何在断网后恢复重传呢

可以用定时器监听网络状态,同时监听FileStatus是fail失败的文件进行手动重传。

断网重传示例

使用window.navigator.onLine获取网络状态,使用定时器定时执行,

//添加定时器
const startInterval = () => {timer.value = setInterval(() => {if (window.navigator.onLine) {//有网络时主动检测是否有失败的if (failFlag) {startTime = null;await awsRequest(fileState, file, key);}}}, 10 * 1000); // 5秒钟,单位为毫秒
};

本文仅对业务逻辑中的部分代码抽离讲解了aws分段上传、重传、重试的方法、具体使用请结合自身的场景进行扩展

相关文章:

javaScript实现客户端直连AWS S3(亚马逊云)文件上传、断点续传、断网重传

写在前面&#xff1a;在做这个调研时我遇到的需求是前端直接对接亚马逊平台实现文件上传功能。上传视频文件通常十几个G、客户工作环境网络较差KB/s&#xff0c;且保证上传是稳定的&#xff0c;支持网络异常断点重试、文件断开支持二次拖入自动重传等。综合考虑使用的Aws S3的分…...

从基建发力,CESS 如何推动 RWA 发展?

2023 年 11 月 30 日&#xff0c;Web3 基金会&#xff08;Web3 Foundation&#xff09;宣布通过 Centrifuge 将部分资金投资于 RWA&#xff08;Real World Assets&#xff0c;真实世界资产&#xff09;&#xff0c;试点投资为 100 万美元。Web3 基金会旨在通过支持专注于隐私、…...

qml写一个自适应登录框

1、前言 写一个可自由伸缩的登录框&#xff0c;&#xff0c;&#xff08;横向上&#xff09; 关键&#xff1a;给相关控件赋予 Layout.fillWidth: true 属性 即可。 2、代码 //main.qml import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQml 2.12 import QtQuic…...

考研高数(导数的定义)

总结&#xff1a; 导数的本质就是极限。 函数在某点可导就必连续&#xff0c;连续就有极限且等于该点的函数值。 例题1&#xff1a;&#xff08;归结原则的条件是函数可导&#xff09; 例题2&#xff1a; 例题3&#xff1a;...

ChatGPT在国际中文教育领域引起的变革与挑战

随着ChatGPT这一先进的自然语言处理模型的出现&#xff0c;教学、学习、测评和辅导的传统方式正在面临可能的重塑。她是否会影响中文教育的未来方向&#xff0c;甚至取代中文教师的角色&#xff0c;成为了许多人热议的话题。本文旨在探讨ChatGPT与中文测评之间的联系&#xff0…...

C语言—基础数据类型(含进制转换)

进制转换不多&#xff0c;但我觉得适合小白(我爱夸自己嘿嘿) 练习 1. 确认基础类型所占用的内存空间(提示&#xff1a;使用sizeof 运算符)&#xff1a; 在这里我说一下&#xff0c;long 类型通常占用 4 字节。在 64 位系统上&#xff0c;long 类型通常也可为 8 字节。 格式…...

警钟长鸣-合同问题

由于去年入职了某家公司&#xff0c;本来想着临时过渡一下&#xff0c;虽然签的时候发现合同和竞业协议存在很明显的问题或者说好听点“限制比较严&#xff1f;”&#xff0c;大部分互联网公司都成了它的假想敌&#xff0c;但是本着来都来了的想法就签了&#xff0c;于是导致发…...

CAN通讯协议学习

介绍 它是一种异步通讯&#xff0c;can_high和can_low两条线利用的是电位差传输信号&#xff0c;抗干扰能力强&#xff0c;但是必须要有can控制器如TJA1050&#xff08;我的开发板&#xff09; 当 CAN 节点需要发送数据时&#xff0c;控制器把要发送的二进制编码通过 CAN_Tx 线…...

Spring Boot 笔记 008 创建接口_获取用户信息

1.1.1 编写userinfo接口 1.1.2 User实体类中增加转json忽略password注释 package com.geji.pojo;import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data;import java.time.LocalDateTime;//lombok 在…...

EMC学习笔记(二十六)降低EMI的PCB设计指南(六)

降低EMI的PCB设计指南&#xff08;六&#xff09; 1.PCB布局1.1 带键盘和显示器的前置面板PCB在汽车和消费类应用中的应用1.2 敏感元器件的布局1.3 自动布线器 2.屏蔽2.1 工作原理2.2 屏蔽接地2.3 电缆屏蔽至旁路2.4 缝隙天线&#xff1a;冷却槽和缝隙 tips&#xff1a;资料主要…...

pytorch花式索引提取topk的张量

文章目录 pytorch花式索引提取topk的张量问题设定代码实现索引方法gather方法验证 补充知识expand方法gather方法randint pytorch花式索引提取topk的张量 问题设定 或者说&#xff0c;有一个(bs, dim, L)的大张量&#xff0c;索引的index形状为(bs, X)&#xff0c;想得到一个(…...

Swagger2

Swagger2 引入依赖 <!-- springfox-swagger2 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.10.5</version></dependency>编写配置 @Configuration public …...

2024/2/13

数组练习 1、选择题 1.1、若有定义语句&#xff1a;int a[3][6]; &#xff0c;按在内存中的存放顺序&#xff0c;a 数组的第10个元素是 D A&#xff09;a[0][4] B) a[1][3] C)a[0][3] D)a[1][4] 1.2、有数组 int a[5] {10&#xff0c;20&#xff0c;30&#xff0c;40&…...

【工具】Android|Android Studio 长颈鹿版本安装下载使用详解

版本&#xff1a;2022.3.1.22&#xff0c; https://redirector.gvt1.com/edgedl/android/studio/install/2022.3.1.22/android-studio-2022.3.1.22-windows.exe 前言 笔者曾多次安装并卸载Android Studio&#xff0c;反复被安卓模拟器劝退。现在差不多是第三次安装&#xff0c…...

第三代互联网web3.0

Web3.0&#xff0c;通常被称为第三代互联网&#xff0c;代表了互联网技术的下一个演进阶段。它主要基于区块链、去中心化和用户赋权的理念构建&#xff0c;旨在创造一个更加智能、开放且安全的网络环境。以下是Web3.0的一些关键特点&#xff1a; 1. **去中心化**&#xff1a;We…...

FL Studio版本升级-FL Studio怎么升级-FL Studio升级方案

已经是新年2024年了&#xff0c;但是但是依然有很多朋友还在用FL Studio12又或者FL Studio20&#xff0c;今天这篇文章教大家如何升级FL Studio21 FL Studio 21是Image Line公司开发的音乐编曲软件&#xff0c;除了软件以外&#xff0c;我们还提供了FL Studio的升级服务&#…...

服务降级(Sentinel)

服务降级 采用 SentinelResource 注解方式实现&#xff0c; 必要的 依赖必须引入 以及 切面Bean 接口代码 RequestMapping("/degrade")SentinelResource(value DEGRADE_RESOURCE_NAME, blockHandler "blockHandlerForDegrade",entryType EntryType.IN…...

Rust入门问题: use of undeclared crate or module `rand`

按照官网学rust&#xff0c;程序地址在这里&#xff0c; 写个猜数字游戏 - Rust 程序设计语言 简体中文版 程序内容也很简单&#xff0c; use std::io; use rand::Rng;fn main() {println!("Guess the number!");let secret_number rand::thread_rng().gen_range…...

2024.2.6 模拟实现 RabbitMQ —— 数据库操作

目录 引言 选择数据库 环境配置 设计数据库表 实现流程 封装数据库操作 针对 DataBaseManager 单元测试 引言 硬盘保存分为两个部分 数据库&#xff1a;交换机&#xff08;Exchange&#xff09;、队列&#xff08;Queue&#xff09;、绑定&#xff08;Binding&#xff0…...

dolphinscheduler海豚调度(一)简介快速体验

1、简介 Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统。适用于企业级场景&#xff0c;提供了一个可视化操作任务、工作流和全生命周期数据处理过程的解决方案。 Apache DolphinScheduler 旨在解决复杂的大数据任务依赖关系&#xff0c;并为应…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...