使用POST将文件上传到s3 [英] Upload file to s3 with POST
问题描述
我想通过 POST接口,但我没有这样做.
I'd like to upload a file to AWS S3 via the POST interface, but I fail to do so.
我已经使它可以与PUT和getSignedUrl
一起使用,但是不幸的是,该接口不允许直接文件大小的限制.因此,我尝试使用POST接口,因为在那里可以使用'content-length-range'
条件.
I've already made it work with PUT and getSignedUrl
, but unfortunately that interface doesn't allow direct file size restrictions. So I tried to use the POST interface, because there I can use 'content-length-range'
condition.
这是我的请求签名:
const aws = require('aws-sdk');
aws.config.update({
signatureVersion: 'v4',
region: 'eu-central-1',
accessKeyId: config.aws.keyId,
secretAccessKey: config.aws.keySecret
});
const s3 = new aws.S3();
return new Promise((resolve, reject) => {
const params = {
Bucket: config.aws.bucket,
Fields: {
key: filePath
},
Expires: config.aws.expire,
Conditions: [
['acl', 'public-read'],
['content-length-range', 0, 10000000] // 10 Mb
]
};
const postUrl = s3.createPresignedPost(params, (err, data) => {
resolve(data);
});
});
这部分似乎还可以,但是我不能使用所需的签名将文件上传到S3.
This part seems to be OK, but I can't use the required signature to upload a file to S3.
这是我做过的其他尝试:
Here are a few other attempts I made:
request.post({
url: payload.url,
body: payload,
form: fs.createReadStream(__dirname + `/${filePath}`)
}, (err, response, body) => {});
另一种尝试:
let formData = payload;
formData.file = fs.createReadStream(__dirname + `/${filePath}`);
request.post({
url: payload.url,
formData: formData
}, (err, response, body) => {});
通过获取:
const fetch = require('node-fetch');
const FormData = require('form-data');
const form = new FormData();
const fields = payload.fields;
for(const field in payload.fields) {
form.append(field, payload.fields[field]);
}
form.append('file', fs.createReadStream(__dirname + `/${filePath}`));
fetch(payload.url, {
method: 'POST',
body: form.toString(),
headers: form.getHeaders()
})
.then((response) => {})
.catch((err) => {});
以上两项都不起作用,它们要么说错误的请求",要么说格式错误的请求".其中之一将某些内容上传到服务器,但该文件不可读.
Neither of these work, they either say 'Bad request', or 'Badly formed request'. One of them uploaded something to the server, but the file was unreadable.
如何为S3存储桶添加最大文件大小限制?
How can I add a max file size limit to an S3 bucket?
更新:
我想我向前走了一点.有了这段代码,我得到了错误响应:You must provide the Content-Length HTTP header.
Update:
I think I move forward just a little. With this code, I get the error response: You must provide the Content-Length HTTP header.
const fetch = require('node-fetch');
const FormData = require('form-data');
const form = new FormData();
form.append('acl', 'public-read');
for(const field in payload.fields) {
form.append(field, payload.fields[field]);
}
form.append('file', fs.createReadStream(__dirname + `/${filePath}`));
fetch(payload.url, {
method: 'POST',
body: form,
headers: form.getHeaders()
})
.then((response) => { return response.text(); })
.then((payload) => { console.log(payload); })
.catch((err) => console.log(`Error: ${err}`));
推荐答案
最后它可行.这是万一有人遇到相同问题的代码.
Finally it works. Here's the code in case anyone has the same problem.
一些注意事项:
- 请求或表单数据库存在错误,其中一个未设置"Content-Lenght"标头.参见问题 https://github.com/request/request/issues/316
- 表单字段的顺序很重要,
acl
乳胶,它将失败. - 那里有不同的AWS协议,您应该检查您所在区域中可用的协议.就我而言,即使在S3构造函数中,我也必须将
signatureVersion
设置为V4
.
- Request or form-data libraries have a bug, one of them doesn't set the 'Content-Lenght' header. See issue https://github.com/request/request/issues/316
- The order of the form fields are important,
acl
latel, it will fail. - There are different AWS protocols out there, you should check the ones available in your zone. In my case, I had to set
signatureVersion
toV4
even in the S3 constructor.
我不为代码质量感到自豪,但最终它奏效了.
I'm not proud of the code quality, but at last it works.
const aws = require('aws-sdk');
const fs = require('fs');
const request = require('request');
const config = require('./config');
let s3;
const init = () => {
aws.config.update({
signatureVersion: 'v4',
region: 'eu-central-1',
accessKeyId: config.aws.keyId,
secretAccessKey: config.aws.keySecret
});
s3 = new aws.S3({signatureVersion: 'v4'});
};
const signFile = (filePath) => {
return new Promise((resolve, reject) => {
const params = {
Bucket: config.aws.bucket,
Fields: {
key: filePath
},
Expires: config.aws.expire,
Conditions: [
['content-length-range', 0, 10000000], // 10 Mb
{'acl': 'public-read'}
]
};
s3.createPresignedPost(params, (err, data) => {
resolve(data);
});
});
};
const sendFile = (filePath, payload) => {
const fetch = require('node-fetch');
const FormData = require('form-data');
const form = new FormData();
form.append('acl', 'public-read');
for(const field in payload.fields) {
form.append(field, payload.fields[field]);
}
form.append('file', fs.createReadStream(__dirname + `/${filePath}`));
form.getLength((err, length) => {
console.log(`Length: ${length}`);
fetch(payload.url, {
method: 'POST',
body: form,
headers: {
'Content-Type': false,
'Content-Length': length
}
})
.then((response) => {
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
return response.text();
})
.then((payload) => {
console.log(payload);
console.log(form.getHeaders());
})
.catch((err) => console.log(`Error: ${err}`));
});
};
init();
const file = 'test.pdf';
const filePath = `files/new/${file}`;
signFile(filePath)
.then((payload) => { sendFile(file, payload); });
这篇关于使用POST将文件上传到s3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!