我正在尝试在Meteor / React应用程序中将图像文件上传到AWS S3存储桶。
我正在使用React Dropzone Uploader。
版本:
METEOR@1.8.1
"react": "^16.11.0"
"react-dropzone-uploader": "^2.11.0"
除了S3存储桶本身之外,所有其他东西都在我的本地开发计算机上运行。
当我将图像拖到浏览器中的dropzone上传器上时,我看到进度条,然后是图像预览,但是控制台显示消息“ error_upload”,并且“提交”按钮被禁用。
如果上传响应的HTTP状态代码> = 400,则根据docs设置error_upload,但是我不明白这是什么意思。图像预览看起来不错,URL已经正确生成,并且我还没有尝试执行实际上传到AWS的操作。
据我所知,一切都以正确的顺序进行:客户端控制台以以下形式记录我的signedUrl:
signedUrl in client https://my-bucket.s3.amazonaws.com/test/DA8acSgM3wQtrReEK/userpic.jpg?AWSAccessKeyId=somekeyid&Expires=1576600622&Signature=somestuff
然后登录“上传”并显示看起来像有效的对象详细信息:
height: 100
id: "1576600322132-0"
lastModifiedDate: "2014-01-21T17:00:42.000Z"
name: "userpic.jpg"
percent: 0
previewUrl: "blob:http://127.0.0.1:3000/80aaa9bd-b7b8-492e-8e13-8c8b971e4998"
size: 5203
status: "uploading"
type: "image/jpeg"
uploadedDate: "2019-12-17T16:32:02.137Z"
width: 100
然后,客户端控制台最终显示:
error_upload
height: 100
id: "1576600322132-0"
lastModifiedDate: "2014-01-21T17:00:42.000Z"
name: "userpic.jpg"
percent: 100
previewUrl: "blob:http://127.0.0.1:3000/80aaa9bd-b7b8-492e-8e13-8c8b971e4998"
size: 5203
status: "error_upload"
type: "image/jpeg"
uploadedDate: "2019-12-17T16:32:02.137Z"
width: 100
这是我的代码:
客户端:
import React from 'react';
import 'react-dropzone-uploader/dist/styles.css';
import Dropzone from 'react-dropzone-uploader';
const callWithPromise = (method, myParameters) => {
return new Promise((resolve, reject) => {
Meteor.call(method, myParameters, (err, res) => {
if (err) reject('Something went wrong');
resolve(res);
});
});
};
const DropzoneUploader = ({ docId }) => {
const getUploadParams = async ({ meta }) => {
const signedUrl = await callWithPromise('getUploadParams', { 'key': `test/${docId}/${meta.name}` });
console.log('signedUrl in client', signedUrl);
return { 'url': signedUrl };
};
// called every time a file's `status` changes
const handleChangeStatus = ({ meta, file }, status) => { console.log(status, meta, file); };
// receives array of files that are done uploading when submit button is clicked
const handleSubmit = (files, allFiles) => {
console.log(files.map((f) => f.meta));
allFiles.forEach((f) => f.remove());
};
return (
<Dropzone
getUploadParams={getUploadParams}
onChangeStatus={handleChangeStatus}
onSubmit={handleSubmit}
accept="image/*,audio/*,video/*"
/>
);
};
export default DropzoneUploader;
服务器:aws.js
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const accessKeyId = process.env.AWS_ACCESS_KEY_ID;
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
AWS.config.update({ 'accessKeyId': accessKeyId, 'secretAccessKey': secretAccessKey });
const myBucket = process.env.AWS_BUCKET;
const signedUrlExpireSeconds = 60 * 5;
const getSignedUrl = (key) => s3.getSignedUrl('putObject', {
'Bucket': myBucket,
'Key': key,
'Expires': signedUrlExpireSeconds,
});
export default getSignedUrl;
服务器:Methods.js
Meteor.methods({
'getUploadParams': function ({ key }) {
const signedUrl = getSignedUrl(key);
console.log('signedUrl on server', signedUrl);
return signedUrl;
},
});
存储桶上的CORS配置:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
对于我做错了什么,我将不胜感激。谢谢!
更新:“网络”标签显示对我的signedUrl的调用禁止使用状态码403“ SignatureDoesNotMatch”,这让我感到惊讶,因为在用户单击浏览器中的“提交”之前,我不认为它将尝试上传文件。所以也许问题出在我的AWS凭证上?但是我想确切地知道此阶段的url请求是什么情况。
更新2:我已将s3.getSignedUrl函数更改为指定“ putObject”而不是“ getObject”,但仍无法正常工作。从“网络”标签中可以看到,请求实际上是作为POST发送的,但是我不知道如何更改它?