当前位置: 首页 > 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;并为应…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...