使用 Axios 进行 Amazon S3 远程文件上传
Posted
技术标签:
【中文标题】使用 Axios 进行 Amazon S3 远程文件上传【英文标题】:Amazon S3 Remote File Upload with Axios 【发布时间】:2019-02-26 18:44:45 【问题描述】:我正在尝试编写一个函数:
-
以远程 URL 作为参数,
使用 axios 获取文件
将流上传到 amazon s3
最后,返回上传的网址
我找到了帮助 here on ***。到目前为止,我有这个:
/*
* Method to pipe the stream
*/
const uploadFromStream = (file_name, content_type) =>
const pass = new stream.PassThrough();
const obj_key = generateObjKey(file_name);
const params = Bucket: config.bucket, ACL: config.acl, Key: obj_key, ContentType: content_type, Body: pass ;
s3.upload(params, function(err, data)
if(!err)
return data.Location;
else
console.log(err, data);
);
return pass;
/*
* Method to upload remote file to s3
*/
const uploadRemoteFileToS3 = async (remoteAddr) =>
axios(
method: 'get',
url: remoteAddr,
responseType: 'stream'
).then( (response) =>
if(response.status===200)
const file_name = remoteAddr.substring(remoteAddr.lastIndexOf('/')+1);
const content_type = response.headers['content-type'];
response.data.pipe(uploadFromStream(file_name, content_type));
);
但是uploadRemoteFileToS3
没有返回任何东西(因为它是一个异步函数)。如何获取上传的url?
更新
我进一步改进了代码并编写了一个类。这是我现在拥有的:
const config = require('../config.json');
const stream = require('stream');
const axios = require('axios');
const AWS = require('aws-sdk');
class S3RemoteUploader
constructor(remoteAddr)
this.remoteAddr = remoteAddr;
this.stream = stream;
this.axios = axios;
this.config = config;
this.AWS = AWS;
this.AWS.config.update(
accessKeyId: this.config.api_key,
secretAccessKey: this.config.api_secret
);
this.spacesEndpoint = new this.AWS.Endpoint(this.config.endpoint);
this.s3 = new this.AWS.S3(endpoint: this.spacesEndpoint);
this.file_name = this.remoteAddr.substring(this.remoteAddr.lastIndexOf('/')+1);
this.obj_key = this.config.subfolder+'/'+this.file_name;
this.content_type = 'application/octet-stream';
this.uploadStream();
uploadStream()
const pass = new this.stream.PassThrough();
this.promise = this.s3.upload(
Bucket: this.config.bucket,
Key: this.obj_key,
ACL: this.config.acl,
Body: pass,
ContentType: this.content_type
).promise();
return pass;
initiateAxiosCall()
axios(
method: 'get',
url: this.remoteAddr,
responseType: 'stream'
).then( (response) =>
if(response.status===200)
this.content_type = response.headers['content-type'];
response.data.pipe(this.uploadStream());
);
dispatch()
this.initiateAxiosCall();
async finish()
//console.log(this.promise); /* return Promise Pending */
return this.promise.then( (r) =>
console.log(r.Location);
return r.Location;
).catch( (e)=>
console.log(e);
);
run()
this.dispatch();
this.finish();
但仍然不知道如何在 promise 被解决时捕获结果。到目前为止,我尝试了这些:
testUpload = new S3RemoteUploader('https://avatars2.githubusercontent.com/u/41177');
testUpload.run();
//console.log(testUpload.promise); /* Returns Promise Pending */
testUpload.promise.then(r => console.log); // does nothing
但以上都不起作用。我有一种感觉,我错过了一些非常微妙的东西。有什么线索吗?
【问题讨论】:
它是https://address-to-your-s3-bucket + path-of-file
。如果您的 ACL 是公开读取的,则此 url 可以正常工作。文件路径是Key
这里
这已经很老了,但我看到你的异步/承诺调用方法没有返回任何东西。例如,在您的 run
方法中,您调用 dispatch
但那里没有 await
。如此多的事情只是变成了“一劳永逸”。任何人,你在这里拥有的骨头我确实觉得很有帮助。谢谢。
【参考方案1】:
上传后,您可以调用 s3 sdk 中的 getsignedurl 函数来获取 url,您还可以在其中指定 url 的到期时间。您需要传递该功能的密钥。现在旅行将在稍后更新示例。
生成一个简单的预签名 URL,允许任何用户查看 您拥有的存储桶中的私有对象的内容,您可以使用 在调用 getSignedUrl() 之后:
var s3 = new AWS.S3();
var params = Bucket: 'myBucket', Key: 'myKey';
s3.getSignedUrl('getObject', params, function (err, url)
console.log("The URL is", url);
);
官方文档链接 http://docs.amazonaws.cn/en_us/AWSjavascriptSDK/guide/node-examples.html
代码必须是这样的
function uploadFileToS3AndGenerateUrl(cb)
const pass = new stream.PassThrough();//I have generated streams from file. Using this since this is what you have used. Must be a valid one.
var params =
Bucket: "your-bucket", // required
Key: key , // required
Body: pass,
ContentType: 'your content type',
;
s3.upload(params, function(s3Err, data)
if (s3Err)
cb(s3Err)
console.log(`File uploaded successfully at $data.Location`)
const params =
Bucket: 'your-bucket',
Key: data.key,
Expires: 180
;
s3.getSignedUrl('getObject', params, (urlErr, urlData) =>
if (urlErr)
console.log('There was an error getting your files: ' + urlErr);
cb(urlErr);
else
console.log(`url: $urlData`);
cb(null, urlData);
)
)
【讨论】:
感谢您的回复。为了使用 getsignedurl 我需要确认上传已经完成。能否请您查看代码并指导我在哪里可以检查上传是否完成? 另外,getsignedurl 给出了一个在给定时间间隔后过期的 url。我不想那样。我想要一个没有过期的网址 您不能同时拥有错误和数据。获取到数据即可确认上传成功。您需要将数据中的密钥作为 getsignedurl 函数的输入传递。 嗯。仍然没有解决我提到的异步问题。我将永远得到undefined
。无法返回promise
设置到期是可选的,我刚才提到如果你想你可以使用它。【参考方案2】:
请检查我是否已更新您的代码可能会对您有所帮助。
/*
* Method to upload remote file to s3
*/
const uploadRemoteFileToS3 = async (remoteAddr) =>
const response = await axios(
method: 'get',
url: remoteAddr,
responseType: 'stream'
)
if(response.status===200)
const file_name = remoteAddr.substring(remoteAddr.lastIndexOf('/')+1);
const content_type = response.headers['content-type'];
response.data.pipe(uploadFromStream(file_name, content_type));
return new Promise((resolve, reject) =>
response.data.on('end', (response) =>
console.log(response)
resolve(response)
)
response.data.on('error', () =>
console.log(response);
reject(response)
)
)
;
*
* Method to pipe the stream
*/
const uploadFromStream = (file_name, content_type) =>
return new Promise((resolve, reject) =>
const pass = new stream.PassThrough();
const obj_key = generateObjKey(file_name);
const params = Bucket: config.bucket, ACL: config.acl, Key: obj_key, ContentType: content_type, Body: pass ;
s3.upload(params, function(err, data)
if(!err)
console.log(data)
return resolve(data.Location);
else
console.log(err)
return reject(err);
);
);
//call uploadRemoteFileToS3
uploadRemoteFileToS3(remoteAddr)
.then((finalResponse) =>
console.log(finalResponse)
)
.catch((err) =>
console.log(err);
);
【讨论】:
以上是关于使用 Axios 进行 Amazon S3 远程文件上传的主要内容,如果未能解决你的问题,请参考以下文章
为啥从远程 AWS S3 服务器下载 json 文件时 axios GET 错误
如何将文件从远程服务器传输到我的 Amazon S3 实例?
如何在不下载文件的情况下搜索amazon S3存储桶中的文件内容
sh 使用Crontab和Amazon EC2上的s3cmd.Red Hat Linux对Amazon S3进行MongoDB自动备份