从 url 下载文件并将其上传到 AWS S3 而不保存 - node.js

Posted

技术标签:

【中文标题】从 url 下载文件并将其上传到 AWS S3 而不保存 - node.js【英文标题】:Download file from url and upload it to AWS S3 without saving - node.js 【发布时间】:2014-04-06 21:00:01 【问题描述】:

我正在编写一个应用程序,它从 url 下载图像,然后使用 aws-sdk 将其上传到 S3 存储桶。

以前我只是像这样下载图像并将它们保存到磁盘。

request.head(url, function(err, res, body)

    request(url).pipe(fs.createWriteStream(image_path));

);

然后像这样将图像上传到 AWS S3

fs.readFile(image_path, function(err, data)
    s3.client.putObject(
        Bucket: 'myBucket',
        Key: image_path,
        Body: data
        ACL:'public-read'
    , function(err, resp) 
        if(err)
            console.log("error in s3 put object cb");
         else  
            console.log(resp);
            console.log("successfully added image to s3");
        
    );
);

但我想跳过将图像保存到磁盘的部分。有什么方法可以pipe 将来自request(url) 的响应发送到变量然后上传?

【问题讨论】:

这可以在 ios 中做同样的事情吗? 【参考方案1】:

这里有一些 javascript 可以很好地做到这一点:

    var options = 
        uri: uri,
        encoding: null
    ;
    request(options, function(error, response, body) 
        if (error || response.statusCode !== 200)  
            console.log("failed to get image");
            console.log(error);
         else 
            s3.putObject(
                Body: body,
                Key: path,
                Bucket: 'bucket_name'
            , function(error, data)  
                if (error) 
                    console.log("error downloading image to s3");
                 else 
                    console.log("success uploading to s3");
                
            ); 
           
    );

【讨论】:

如所写,代码一次将整个主体加载到内存中(作为字符串加载到“body”变量中)。也就是说,这不会直接从请求流向 S3。 OTOH,如果“encoding”为空,request 将为“body”创建一个 Buffer 对象;见github.com/request/request#requestoptions-callback。我建议对此答案进行编辑,将encoding:'binary' 更改为encoding:null 并消除body=new Buffer(body,'binary')。这将消除将整个“正文”存储在内存中的需要,我认为这与原始问题和答案一致。但评论想要评论...... 我尝试了你的方法,无论是隐式编码还是显式编码,我发现我上传的 png 文件由于某种原因已损坏,无法弄清楚原因。试图复制这张图片openclipart.org/image/250px/svg_to_png/264091/MirrorCarp.png,这就是我在我的桶里得到的images.quickhunts.com/clipart/23234234234.png @Ilanlewin 它绝对适用于png 图像,但请确保您正确实施fs.readFile。自从我最初写这个答案以来,它可能已经改变了,你可能需要更具体的编码。也可以尝试一些jpgs 或其他通用图像。 我试图将 PDF 从远程 URL 存储到 S3。但上传后PDF已损坏。 @ArmadilloJim 对encoding: null 的修复似乎对我有用。 我想将此解决方案应用于我的应用,但请求模块已弃用我想使用 axios 迁移代码有人可以帮助我吗?【参考方案2】:

这就是我所做的并且效果很好:

const request = require('request-promise')
const AWS = require('aws-sdk')
const s3 = new AWS.S3()

const options = 
    uri: uri,
    encoding: null
;

async load() 

  const body = await request(options)
  
  const uploadResult = await s3.upload(
    Bucket: 'bucket_name',
    Key   : path,
    Body  : body,   
  ).promise()
  

【讨论】:

能否指定路径参数【参考方案3】:

这样的事情呢:

const stream = require('stream');
const request = require('request');
const s3 = new AWS.S3()

const pass = new stream.PassThrough();

request(url).pipe(pass);

s3.upload(
    Bucket: 'bucket_name',
    Key: path,
    Body: pass,
);

【讨论】:

【参考方案4】:

你可以像这样用 Axios 实现。更多信息请参考this。

const axios = require("axios");
const AWS = require("aws-sdk");
const  PassThrough  = require("stream");

const s3 = new AWS.S3(
  accessKeyId: "accessKeyId",
  secretAccessKey: "accessKey",
  region: "region",
);

const bucket = "BucketName";
const key = "key";

const uploadToS3 = async (bucket, key) => 
  try 
    const stream = await axios.get(url,  responseType: "stream" );

    const passThrough = new PassThrough();

    const response = s3.upload( Bucket: bucket, Key: key, Body: passThrough );

    stream.data.pipe(passThrough);

    return response.then((data) => data.Location).catch((e) => console.error(e));
   catch (error) 
    console.error(error);
  
;

uploadToS3(bucket, key);

【讨论】:

【参考方案5】:
import axios from "axios";
import aws from 'aws-sdk'
import crypto from 'crypto'

const s3 = new aws.S3();

export const urlToS3 = async ( url, bucket = "rememoio-users", key = Date.now() + crypto.randomBytes(8).toString('hex') + ".png" ) => 
  try 
    const  data  = await axios.get(url,  responseType: "stream" );

    const upload = await s3.upload(
      Bucket: bucket,
      ACL: 'public-read',
      Key: key,
      Body: data,
    ).promise();

    return upload.Location;
   catch (error) 
    console.error(error);
    throw new Error;
  
;

【讨论】:

以上是关于从 url 下载文件并将其上传到 AWS S3 而不保存 - node.js的主要内容,如果未能解决你的问题,请参考以下文章

使用nodejs中的AWS Lambda函数上传音频文件

如何在aws控制台上将war文件从s3上传到EBS环境

Android-Amplify:使用 Amplify 向/从 AWS S3 上传/下载文件

使用其预签名 URL 从 AWS s3 读取文件的内容

使用带有 Node.js 的 AWS Lambda 函数从 S3 存储桶中提取 zip 文件并上传到另一个存储桶

如何使用aws java sdk将文件从S3存储桶从一个区域复制到另一个区域?