如何使用适用于浏览器的 aws-sdk V3 跟踪到 S3 的上传进度 (javascript)

2024-03-16

我可以在网上找到很多关于如何使用 aws-sdk V2 跟踪上传到 S3 的进度的资源,监听如下事件:

.on('httpUploadProgress', event => {}

但自从我将 aws-sdk 更新到 V3 后,就不再有侦听器了。我相信我现在必须使用中间件功能,但我尝试了一些方法但没有成功。我也曾深入API参考文档 https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/index.htmlgithub 存储库 https://github.com/aws/aws-sdk-js-v3没有成功。

我当前的代码是这样的:

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

export const UploadToS3 = (credentials, fileData) => {

    const s3 = new S3Client({
        region: credentials.region,
        credentials: {
            accessKeyId: credentials.access_key,
            secretAccessKey: credentials.secret_key,
            sessionToken: credentials.session_token,
        }
    });

    return new Promise((resolve) => {
        s3.send(new PutObjectCommand({
            Bucket: credentials.bucket,
            Key: credentials.file,
            Body: fileData,
        }));
    });
};

任何帮助,将不胜感激


我遇到了完全相同的问题(从 aws-sdk v2 切换到 v3),并发现这是因为该库使用Fetch https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch所有 HTTP 请求的 API 和Fetch (尚)不支持跟踪上传进度 https://stackoverflow.com/questions/35711724/upload-progress-indicators-for-fetch

为了解决这个问题我交换了Fetch由好老XMLHttpRequest至少对于PUT请求,您可以通过提供自定义来完成请求处理器初始化S3Client时。

import { S3Client } from '@aws-sdk/client-s3';

const myHttpHandler = new MyHttpHandler();
myHttpHandler.onProgress$.subscribe(progress => {
  const percentComplete = progress.progressEvent.loaded / progress.progressEvent.total * 100;
  console.log('upload progress', percentComplete);
});

const myClient = new S3Client({
  endpoint: this.configService.s3Api,
  region: 'eu',
  credentials: { ... },
  requestHandler: myHttpHandler
});

自定义请求处理程序只是扩展FetchHttpHandler来自@aws-sdk/fetch-http-handler。如果该方法是PUT并且有一个正文(所以我们想上传一些东西),它使用自定义 XHR 处理程序 - 否则它只使用Fetch来自它的处理程序super班级。 在 XHR 处理程序中,您可以将某些内容绑定到progressXHR 处理程序的事件 - 在我的例子中,我发出一个 rxjsSubject我可以在自定义处理程序之外使用它。

import { FetchHttpHandler, FetchHttpHandlerOptions } from '@aws-sdk/fetch-http-handler';
import { HeaderBag, HttpHandlerOptions } from '@aws-sdk/types';
import { buildQueryString } from '@aws-sdk/querystring-builder';
import { HttpResponse, HttpRequest } from '@aws-sdk/protocol-http';
import { Subject } from 'rxjs';

class MyHttpHandler extends FetchHttpHandler {
  private myRequestTimeout;

  onProgress$: Subject<{ path: string, progressEvent: ProgressEvent }> = new Subject();

  constructor({ requestTimeout }: FetchHttpHandlerOptions = {}) {
    super({ requestTimeout });
    this.myRequestTimeout = requestTimeout;
  }

  handle(request: HttpRequest, { abortSignal }: HttpHandlerOptions = {}): Promise<{ response: HttpResponse }> {
    // we let XHR only handle PUT requests with body (as we want to have progress events here), the rest by fetch
    if (request.method === 'PUT' && request.body) {
      return this.handleByXhr(request, { abortSignal });
    }
    return super.handle(request, { abortSignal });
  }

  /**
   * handles a request by XHR instead of fetch
   * this is a copy the `handle` method of the `FetchHttpHandler` class of @aws-sdk/fetch-http-handler
   * replacing the `Fetch`part with XHR
   */
  private handleByXhr(request: HttpRequest, { abortSignal }: HttpHandlerOptions = {}): Promise<{ response: HttpResponse}> {
    const requestTimeoutInMs = this.myRequestTimeout;

    // if the request was already aborted, prevent doing extra work
    if (abortSignal?.aborted) {
      const abortError = new Error('Request aborted');
      abortError.name = 'AbortError';
      return Promise.reject(abortError);
    }

    let path = request.path;
    if (request.query) {
      const queryString = buildQueryString(request.query);
      if (queryString) {
        path += `?${queryString}`;
      }
    }

    const { port, method } = request;
    const url = `${request.protocol}//${request.hostname}${port ? `:${port}` : ''}${path}`;
    // Request constructor doesn't allow GET/HEAD request with body
    // ref: https://github.com/whatwg/fetch/issues/551
    const body = method === 'GET' || method === 'HEAD' ? undefined : request.body;
    const requestOptions: RequestInit = {
      body,
      headers: new Headers(request.headers),
      method,
    };


    const myXHR = new XMLHttpRequest();
    const xhrPromise = new Promise<{headers: string[], body: Blob, status: number}>((resolve, reject) => {
      try {
        myXHR.responseType = 'blob';

        // bind the events
        myXHR.onload = progressEvent => {
          resolve({
            body: myXHR.response,
            headers: myXHR.getAllResponseHeaders().split('\n'),
            status: myXHR.status
          });
        };
        myXHR.onerror = progressEvent => reject(new Error(myXHR.responseText));
        myXHR.onabort = progressEvent => {
          const abortError = new Error('Request aborted');
          abortError.name = 'AbortError';
          reject(abortError);
        };

        // progress event musst be bound to the `upload` property
        if (myXHR.upload) {
          myXHR.upload.onprogress = progressEvent => this.onProgress$.next({ path, progressEvent });
        }


        myXHR.open(requestOptions.method, url);
        // append headers
        if (requestOptions.headers) {
          (requestOptions.headers as Headers).forEach((headerVal, headerKey, headers) => {
            if (['host', 'content-length'].indexOf(headerKey.toLowerCase()) >= 0) {
              // avoid "refused to set unsafe header" error message
              return;
            }

            myXHR.setRequestHeader(headerKey, headerVal);
          });
        }
        myXHR.send(requestOptions.body);
      } catch (e) {
        console.error('S3 XHRHandler error', e);
        reject(e);
      }
    });

    const raceOfPromises = [
      xhrPromise.then((response) => {
        const fetchHeaders = response.headers;
        const transformedHeaders: HeaderBag = {};

        fetchHeaders.forEach(header => {
          const name = header.substr(0, header.indexOf(':') + 1);
          const val =  header.substr(header.indexOf(':') + 1);
          if (name && val) {
            transformedHeaders[name] = val;
          }
        });

        const hasReadableStream = response.body !== undefined;

        // Return the response with buffered body
        if (!hasReadableStream) {
          return response.body.text().then(body => ({
            response: new HttpResponse({
              headers: transformedHeaders,
              statusCode: response.status,
              body,
            }),
          }));
        }
        // Return the response with streaming body
        return {
          response: new HttpResponse({
            headers: transformedHeaders,
            statusCode: response.status,
            body: response.body,
          }),
        };
      }),
      this.requestTimeoutFn(requestTimeoutInMs),
    ];
    if (abortSignal) {
      raceOfPromises.push(
        new Promise<never>((resolve, reject) => {
          abortSignal.onabort = () => {
            myXHR.abort();
          };
        })
      );
    }
    return Promise.race(raceOfPromises);
  }

  private requestTimeoutFn(timeoutInMs = 0): Promise<never> {
    return new Promise((resolve, reject) => {
      if (timeoutInMs) {
        setTimeout(() => {
          const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
          timeoutError.name = 'TimeoutError';
          reject(timeoutError);
        }, timeoutInMs);
      }
    });
  }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用适用于浏览器的 aws-sdk V3 跟踪到 S3 的上传进度 (javascript) 的相关文章

  • 无法将消息发布到服务工作人员,因为控制器值为空

    我正在尝试做一个website https secure depths 31934 herokuapp com 在 Service Worker 的帮助下可以离线使用 以缓存页面所需的文件 我试图让用户控制他希望缓存的图像 为此 我使用一个
  • 如何在 Lambda 中将对象上传到 S3?

    似乎无法将对象上传到 Lambda 中的 S3 本地一切正常 日志中没有错误可以显示出了什么问题 代码如下 console log Loading function var AWS require aws sdk var s3 new AW
  • Javascript“this”在 IE 中丢失上下文

    以下在 firefox safari chrome 中工作正常 在 IE 中 this 似乎在 handleEvent 函数中丢失上下文 警报的结果是 object Window 这不是我想要的 当从handleEvent 输出时 this
  • 如何使用标准 JavaScript 在 CSS 转换结束后立即重新启动它?

    我构建了一种密码生成器 只要倒计时到期 它就会显示新密码 不幸的是 我只设法弄清楚如何运行我的代码一次 倒计时由一个简单的 CSS 过渡组成 我想保留它 因为它比我的其他尝试平滑得多 其中我尝试使用 JavaScript 重复更新宽度 va
  • Mongoose 查询执行后回调函数从未被调用

    以下是我的代码 mongoose connect mongodb localhost mydatabase var db mongoose connection db on error console error bind console
  • 多次训练brain.js?

    在第一次训练后 如何将新信息 仅新信息 而不是所有信息 因为这会花费太多性能 训练到我的用 Brain js 制作的神经网络 它有点粗糙 但您可以使用以下结构来实现 如果我们加入 2 个训练数据集 旧数据集与新数据集 然后重新训练keepN
  • 如何使传单圆圈标记可拖动?

    使用传单 我创建了一个L circleMarker我希望它是可拖动的 var marker L circleMarker new L LatLng 48 94603 2 25912 draggable true bindPopup Circ
  • html 图像 src 调用 javaScript 变量

    这是我的代码 我想问 我怎样才能做到这一点 img src img apple 我一直在尝试使用 call 函数和 document onload 但它根本不起作用 有人可以救我吗 我假设你只是想用 javascript 更新图像 src
  • 个人 Tumblr 帖子上的 Javascript

    我知道您可以编辑在 tumblr 博客上呈现所有帖子博客主页的 html AngularJS 但是 有什么办法可以添加自定义到各个帖子 我想在逐个帖子的基础上做一些 javascript 的东西 但似乎无法找到可以编辑代码的位置 或者 如果
  • 如何用 JavaScript 修复图像透视变形和旋转?

    我有一些用手机拍摄的图像 有没有可以拉直纸张照片并将其压平的 JavaScript 库 例如 我想创建一个矩形图像 该图像没有任何失真 换句话说我想知道如何用 JavaScript 修复透视变形和旋转 例如 我发现下面的示例图像来自this
  • 使用 Boto3 以字符串形式打开 S3 对象

    我知道使用 Boto 2 可以使用以下命令将 S3 对象作为字符串打开 get contents as string http boto readthedocs org en latest ref file html highlight c
  • 只保留 A-Z 0-9 并使用 javascript 从字符串中删除其他字符

    我正在尝试验证字符串以使它们成为有效的网址 我只需要保留 A Z 0 9 并使用以下命令从字符串中删除其他字符javascript or jquery 例如 贝儿餐厅 我需要将其转换为 百丽餐厅 所以字符被删除 只保留 A Z a z 0
  • Javascript location.href 到 mailto 触发 GET HTTP,该 HTTP 在 Chrome 中被取消

    我有一个按钮可以触发以下 javascript 函数 function sendEmail var mail mailto email protected cdn cgi l email protection location href m
  • AWS CLI 从 AWS CLI 获取私有存储桶的下载 S3 URL

    我可以将文件上传到private使用以下命令成功S3存储桶 aws s3 cp myfile txt s3 myfolder myfile txt region us east 1 output json 我想发出 AWS CLI 命令来返
  • 在 javascript 中实现固定位置会导致 Safari 滚动时出现抖动

    固定位置不适用于我的用例 因为它固定在浏览器窗口上 您可能会处于文本在屏幕右侧之外且无法到达的状态 无论如何 我尝试使用绝对定位 然后调整javascript中的 顶部 它在 Firefox 和 Chrome 中运行良好 但在 Safari
  • ES6 静态方法引用 self? [复制]

    这个问题在这里已经有答案了 我有两节课 存储库和用户存储库 我想在 Repository 中定义一个静态方法 该方法在运行时调用 UserRepository 中的静态函数 有什么干净的方法可以做到这一点吗 class Repository
  • 如何在 Javascript 中连接 C# ActiveX 事件处理程序

    我尝试使用几个代码片段将 ActiveX 对象与 Javascript 事件处理程序挂钩 我无法确定为什么事件处理程序没有被调用 带有项目的 Github 存储库 https github com JesseKPhillips Csharp
  • 如何在亚马逊 EC2 上调试 python 网站?

    我是网络开发新手 这可能是一个愚蠢的问题 但我找不到可以帮助我的确切答案或教程 我工作的公司的网站 用 python django 构建 托管在亚马逊 EC2 上 我想知道从哪里开始调试这个生产站点并检查存储在那里的日志和数据库 我有帐户信
  • Safari 扩展将消息发送到特定选项卡

    有没有办法从全局页面发送消息到特定选项卡 我目前正在做的是 在创建选项卡时 注入的脚本会创建一个唯一的 ID 并将包含该编号的消息发送到全局页面 并且全局页面会保存该编号 如果全局页面需要发送一些数据到一个tab 即 tab 3 然后全局页
  • 使用
    元素作为 JavaScript 代码的输入。这是最好的方法吗?

    各位 显然 我是编码新手 所以最近完成了一些有关 HTML 和 Javascript 的 Lynda 课程后 我的简单 HTML 页面遇到了困难 基本上 我想要的是使用 JavaScript 进行基本计算 让用户使用 HTML 输入两个数字

随机推荐

  • ANR(强制关闭/等待),同时生成足够大的列表

    我正在创建一种文件资源管理器 其中如果将任何应用程序文件复制到手机 SD 卡 我将在带有对话框主题的活动中向用户显示它 对于复制的每个新 app apk 我都会将应用程序的名称和位置附加到对话框中 并且列表是可滚动的 我的问题是 如果我一次
  • 使用 Fast API 接收图像,使用 cv2 处理然后返回

    我正在尝试构建一个 API 它接收图像并对其进行一些基本处理 然后使用 Open CV 和 Fast API 返回它的更新副本 到目前为止 我的接收器工作得很好 但是当我尝试对处理后的图像进行 Base64 编码并将其发送回时 我的移动前端
  • 类型错误:无法深度复制此模式对象

    试图理解我的 变量 类中的这个错误 我希望在我的 Variable 类中存储 sre SRE Pattern 我刚刚开始复制 Variable 类 并注意到它导致我的所有 Variable 类实例发生更改 我现在明白我需要深度复制此类 但现
  • CAPL 编程使用 Timer 作为延迟

    我一直在编写一个 CAPL 脚本 它会在一定的延迟后在每个通道 2 个 上发送消息 我想使用生成以下延迟设置定时器 and mtimer 正在运行功能 我可以使用 setTimer 函数 但我不知道如何使用mtimer 正在运行 代码如下所
  • PhoneGap / Android 自定义键盘

    我正在开发一个具有多个input type numer 元素 目前仅限安卓 内置数字键盘有两个问题 it s inconsistent different on different versions of Android it has un
  • 如何向 ASP.NET 中的元素添加多个类?

    我正在尝试以编程方式将第二个类添加到 td C 中的元素 我想要添加类的元素已经分配了一个类 如果我做类似的事情 myObject CssClass MyClass 它只是覆盖原来的类 我想我可以做类似的事情 myObject CssCla
  • 关于*管理*测试驱动和/或敏捷开发的最佳具体“操作手册”? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一本易于理解的书来呈现给我的老板 团队 背景资料 我们越来越多的工作会议让我的老板 团队思考
  • R Shiny - 条件面板中的条件面板

    我想知道是否可以在另一个条件面板中包含一个条件面板 例如 如果我有一个包含两个选项的下拉列表 1 和 2 选择 1 将显示一组选项 选择 2 将显示另一组选项 但是是否可以在这些条件面板中嵌套一个条件面板 以便我可以在选项 1 的输入中拥有
  • Javascript - 在单词中拖动字母(重新排列)

    我目前正在开发一款名为 词洗牌 http wordshuffle bplaced net 目前单词是德语 用于测试目的 如果你想玩的话 我的进步进展顺利 但我决定改变你玩游戏的方式 目前 您必须通过在文本字段中输入您的猜测来猜测该单词 所以
  • 错误:无法连接到系统 d-bus:未安装 d-bus

    我现在使用 Virtual Box 启动 VM 版本是 5 1 26 r117224 Qt5 6 2 但是当我尝试启动 VM 时 我看到以下错误消息 00 00 29 246866 VMMDev Guest Log 00 00 00 000
  • 实体框架和分片数据库

    我有一个 WCF 数据服务在实体框架代码优先 4 1 提供程序之上运行 该数据库相当大 一个关键表有 77 百万条记录 并且每月增长约 10 并且出现了相当大的性能问题 虽然对这么大的数据库进行分片是一件痛苦的事情 但这似乎是不可避免的 我
  • 用于多行注释的 Unix Flex 正则表达式

    我正在 Unix 上使用 Flex 制作词法分析器 如果您之前使用过它 您就会知道您主要只是为您为其编写词法分析器的任何语言的标记定义正则表达式 我被困在最后一部分 我需要正确的正则表达式来进行多行注释 以允许类似的事情 This is a
  • MATLAB:两个矩阵在一个索引上的逐元素乘法?

    我试图弄清楚是否有一种本地方法可以在 Matlab 中获得两个矩阵的某种元素乘积 我正在寻找的产品需要两个矩阵 A and B说 并返回那里的产品C 其元素由下式给出 C i j k A i j B j k 自然地 列数A假设与行数相同B
  • 为什么 ui.alert 可以工作,但 ui.prompt 不能与 onOpen() 一起使用?

    当我使用 onOpen 时 我可以创建一个弹出窗口 ui alert 但 ui prompt 不起作用 例如 function onOpen var ui SpreadsheetApp getUi get ui for alert ui a
  • 我是否有 gcc 优化错误或 C 代码问题?

    测试以下代码 include
  • 我可以通过编程方式创建 Google 帐户吗?

    有谁知道是否通过java中的google api 我可以以编程方式创建谷歌帐户 Yes ish 管理 SDK https developers google com admin sdk Directory API 允许您创建可与 Googl
  • 在nodejs中写入文件之前对数据流进行排序

    我有一个输入文件 可能包含最多 1M 条记录 每条记录如下所示 field 1 field 2 field3 n 我想读取这个输入文件并根据field3在将其写入另一个文件之前 这是我到目前为止所拥有的 var fs require fs
  • 如何将业务逻辑和电子邮件发送功能分开?

    我的 Java Web 应用程序有一个要求 需要在某些条件下发送电子邮件警报 为此 我使用了 javax mail api 并且发送电子邮件效果很好 但问题是程序执行要等到发送电子邮件的方法执行完毕为止 由于在各个点要发送数百封电子邮件 这
  • 将结构(或类)从 C++ dll 传递到 C# (Unity 3D)

    我正在编写一个包装器以从传感器获取一些数据 虽然我在传递 int float 和它们的数组方面没有问题 但我很难掌握如何传递结构 代码总结 C side 结构如下 struct HandInfo int id float x y z 在某一
  • 如何使用适用于浏览器的 aws-sdk V3 跟踪到 S3 的上传进度 (javascript)

    我可以在网上找到很多关于如何使用 aws sdk V2 跟踪上传到 S3 的进度的资源 监听如下事件 on httpUploadProgress event gt 但自从我将 aws sdk 更新到 V3 后 就不再有侦听器了 我相信我现在