【问题标题】:How to download file from AWS S3 using getObject in Reactjs?如何在 Reactjs 中使用 getObject 从 AWS S3 下载文件?
【发布时间】:2021-06-08 11:52:40
【问题描述】:

我正在尝试使用 React 直接从客户端将 S3 存储桶中的文件下载为 .csv 格式。我已经能够上传文件没有问题,甚至列出了存储桶中的所有文件,但是在使用 getObject 实际下载文件时遇到了麻烦。我想要的文件保存在 templates 文件夹中,因此当从下拉列表中选择一个时,我的参数中的 Key 会更改,并将获取该特定文件。

我已尝试使用 Blob 获取通过在特定存储桶和文件本身上调用 getObject 接收到的 data.Body,但遇到一些文件无法下载或在 Mac OS 上运行但在 Mac OS 上无法运行的问题Windows,或者不能在 Firefox 上运行,但可以在 Chrome 中运行,反之亦然。

我想知道是否有一种简单的方法可以仅使用 React 来做到这一点?从文件中获取数据并将其转换为 .csv?

这是我的 Downloads.js 文件,使用 React Bootstrap 作为下拉菜单可以选择特定的文件名:

import React, { useState } from 'react';
import { ListGroup, Dropdown } from 'react-bootstrap';
import AWS from 'aws-sdk';

const InputDownload = () => {
  const [template, setTemplate] = useState('Choose Template');

  AWS.config.update({
    accessKeyId: process.env.REACT_APP_ACCESS_ID,
    secretAccessKey: process.env.REACT_APP_ACCESS_KEY,
  });

  const handleDownload = () => {
    const s3 = new AWS.S3();

    const params = {
      Bucket: process.env.REACT_APP_INTERNAL_BUCKET_NAME,
      Key: `templates/${template}`,
    };

    s3.getObject(params, (err, data) => {
      if (err) {
        console.log(err, err.stack);
      } else {
        console.log(data.Body.toString();
      }
    });

}

  return (
    <>
      <form className='bg-white my-4'>
        <Dropdown>
          <Dropdown.Toggle variant='secondary' id='dropdown-basic'>
            {template}
          </Dropdown.Toggle>

          <Dropdown.Menu>
            <Dropdown.Item onSelect={() => setTemplate('T1')}>
              T1</Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('IV1')}>
              IV1
            </Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('IV2')}>
              IV2
            </Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('DV1')}>
              DV1
            </Dropdown.Item>
            
          </Dropdown.Menu>
        </Dropdown>
        <input
          type='submit'
          value='Download'
          className='btn btn-primary btn-block mt-3'
          onClick={handleDownload}
        />
      
      </form>
    </>
  );
};

export default InputDownload;

任何帮助将不胜感激!

【问题讨论】:

  • 您的目标是什么?是读取文件的内容,以便您的 React 应用程序可以以某种方式使用该内容,还是将文件实际下载到用户的计算机?此应用程序是否有服务器端组件可以代表客户端进行 AWS API 调用?
  • 感谢您的回复。目标是让客户端的用户能够以 csv 格式下载文件。实际上,我最终想出了如何使用 Blob 来做到这一点,但由于某些功能被弃用而出现了问题。我现在会自己回答这个问题,非常感谢!

标签: javascript reactjs amazon-web-services amazon-s3 export-to-csv


【解决方案1】:

出于安全原因,我强烈建议在服务器端执行此操作。因为在 node 环境中为您的 react 项目执行构建过程后,您的所有环境变量将直接设置为客户端上的字符串,每个人都可以访问它们(accessKeyId 和 secretAccessKey)。

客户端(浏览器或任何其他环境)无权访问您的服务器环境,这就是您在构建过程中传递这些变量的原因。

另一方面,服务器可以直接访问运行它的机器,这就是为什么在服务器端安全地使用环境变量的原因。

【讨论】:

  • 感谢您的提醒、注意并感谢您的建议!
【解决方案2】:

对于将来可能希望直接从客户端执行此操作的其他人,我可以通过使用 Blob 将数据转换为 Blob URL 然后在 下载 时运行该函数来实现此功能> 被点击。

我上面的 InputDownload 文件现在看起来像这样:

import React, { useState } from 'react';
import { ListGroup, Dropdown } from 'react-bootstrap';
import AWS from 'aws-sdk';

const InputDownload = () => {
  const [template, setTemplate] = useState('Choose Template');

  AWS.config.update({
    accessKeyId: process.env.REACT_APP_ACCESS_ID,
    secretAccessKey: process.env.REACT_APP_ACCESS_KEY,
  });

const handleClick = (e) => {
    e.preventDefault();
  };

  const handleDownload = () => {
    const s3 = new AWS.S3();

    const params = {
      Bucket: process.env.REACT_APP_INTERNAL_BUCKET_NAME,
      Key: `templates/${template}`,
    };


    function downloadBlob(blob, name = `${template}.csv`) {
      // Convert your blob into a Blob URL (a special url that points to an object in the browser's memory)
      const blobUrl = URL.createObjectURL(blob);
      // Create a link element
      const link = document.createElement('a');
      // Set link's href to point to the Blob URL
      link.href = blobUrl;
      link.download = name;
      // Append link to the body
      document.body.appendChild(link);
      // Dispatch click event on the link
      // This is necessary as link.click() does not work on the latest firefox
      link.dispatchEvent(
        new MouseEvent('click', {
          bubbles: true,
          cancelable: true,
          view: window,
        })
      );

      // Remove link from body
      document.body.removeChild(link);
    }

    s3.getObject(params, (err, data) => {
      if (err) {
        console.log(err, err.stack);
      } else {
        let csvBlob = new Blob([data.Body.toString()], {
          type: 'text/csv;charset=utf-8;',
        });
        downloadBlob(csvBlob, `${template}`);
      }
    });

}

  return (
    <>
      <form className='bg-white my-4' onSubmit={handleClick}>
        <Dropdown>
          <Dropdown.Toggle variant='secondary' id='dropdown-basic'>
            {template}
          </Dropdown.Toggle>

          <Dropdown.Menu>
            <Dropdown.Item onSelect={() => setTemplate('T1')}>
              T1</Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('IV1')}>
              IV1
            </Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('IV2')}>
              IV2
            </Dropdown.Item>
            <Dropdown.Item onSelect={() => setTemplate('DV1')}>
              DV1
            </Dropdown.Item>
            
          </Dropdown.Menu>
        </Dropdown>
        <input
          type='submit'
          value='Download'
          className='btn btn-primary btn-block mt-3'
          onClick={handleDownload}
        />
      
      </form>
    </>
  );
};

export default InputDownload;

【讨论】:

    【解决方案3】:

    你可以这样做,但你可以在 ReactJS 中使用 Axios

    new Observable((observer) => {
          var xhr = new XMLHttpRequest();
          xhr.open("get", fileURL, true);
          xhr.responseType = "blob";
          xhr.onload = function () {
            if (xhr.readyState === 4) {
              observer.next(xhr.response);
              observer.complete();
            }
          };
          xhr.send();
        }).subscribe((blob: any) => {
          let link = document.createElement("a");
          link.href = window.URL.createObjectURL(blob);
          link.download = elem.material.driverUrl;
          link.click();
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      • 1970-01-01
      • 2018-10-10
      • 1970-01-01
      • 2019-03-24
      • 1970-01-01
      相关资源
      最近更新 更多