如何使用 signedURLs 和 ReactJS 将文件保存到 AWS?
How to save files into AWS using signedURLs and ReactJS?
我正在尝试将带有常规文本输入的图像附加到我的表单中,以便提交到我的 MongoDB。
这就是我创建 post 的函数的样子:
const [postData, setPostData] = useState({
text: '',
images: null,
postedto: auth && auth.user.data._id === userId ? null : userId
});
const { text, images, postedto } = postData;
const handleChange = name => e => {
setPostData({ ...postData, [name]: e.target.value, images: e.target.files });
};
const createPost = async e => {
e.preventDefault();
await addPost(postData, setUploadPercentage);
};
从那里开始我的操作 addPost;在这个函数上我调用了两个 API 路由:
// @route POST api/v1/posts
// @description Add post
// @access Private
// @task DONE
export const addPost = (formData, setUploadPercentage) => async dispatch => {
try {
// ATTACH FILES
let fileKeys = [];
for(let file of formData.images) {
const uploadConfig = await axios.get(`${API}/api/v1/uploads/getS3url?type=${file.type}`);
await axios.put(uploadConfig.data.url, file, {
headers: {
'Content-Type': file.type
}
});
fileKeys.push(uploadConfig.data.key);
}
console.log(fileKeys);
// INSERT NEW BLOG
const config = {
headers: {
'Content-Type': 'multipart/form-data; application/json'
},
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
// Clear percentage
setTimeout(() => setUploadPercentage(0), 10000);
}
};
formData.images = fileKeys;
const res = await axios.post(`${API}/api/v1/posts`, formData, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};
我的 getS3url 函数看起来完全像这样:
exports.uploadFile = asyncHandler(async (req, res, next) => {
const { type } = req.query;
const fileExtension = type.substring(type.indexOf('/') + 1);
const key = `${process.env.WEBSITE_NAME}-${req.user._id}-${
req.user.email
}-${Date.now().toString()}.${fileExtension}`;
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: key,
ContentType: type
};
s3.getSignedUrl(`putObject`, params, (err, url) => {
if (err) {
return next(
new ErrorResponse(
`There was an error with the files being uploaded`,
500
)
);
}
return res.status(201).json({ success: true, key: url });
});
});
我想指出,每个 post 可能有多个图像文件,函数应该 return 为每个文件签名 URL;假设我上传了两个文件,然后我应该检索两个 URLS 以便将它们附加到我的 post.
我确定我管理状态以提交数据的方式没有任何问题,因为它总是 return 我在 console.log(postData)
上使用时所期望的,甚至显示文件。
现在我假设问题出在我的操作上,尤其是 /// INSERT NEW BLOG
注释之前的代码,因为当我 console.log(fileKeys)
什么都没有 returned,甚至 error/undefined/null.....我什么都不是!
我的 uploadFile 在与单个文件一起使用时工作正常....不是真的,因为是的,它 return 是 'supposed' 上传文件的 URL 但是当我进入我的 AWS console/bucket,什么都没有..但那是它自己的 post。
我需要什么帮助?
好吧,我正在尝试使用签名 URL 将 one/multiple 文件上传到我的 AWS,并将它们作为字符串 return 附加到我的 post 中。我的动作文件有问题吗?
谢谢!!
对于我的情况,我一直在遍历图像并生成带符号的 URLs 并返回它们,因为 s3 不支持一次用于多个文件的带符号 URL 选项。
最后我找到了自己的解决方案,这里是:
export const addPost = (formData, images, setUploadPercentage) => async dispatch => {
try {
let fileKeys = [];
for(let i = 0; i < images.length; i++) {
/// STEP 3
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const uploadConfig = await api.get(`/uploads/getS3url?name=${images[i].name}&type=${images[i].type}&size=${images[i].size}`);
// STEP 1
delete api.defaults.headers.common['Authorization'];
await api.put(uploadConfig.data.postURL, images[i], {
headers: {
'Content-Type': images[i].type
}
});
fileKeys.push(uploadConfig.data.getURL);
}
// INSERT NEW BLOG
const config = {
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
setTimeout(() => setUploadPercentage(0), 10000);
}
};
// STEP 2
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const res = await api.post(`/posts`, {...formData, images: fileKeys}, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};
我正在尝试将带有常规文本输入的图像附加到我的表单中,以便提交到我的 MongoDB。
这就是我创建 post 的函数的样子:
const [postData, setPostData] = useState({
text: '',
images: null,
postedto: auth && auth.user.data._id === userId ? null : userId
});
const { text, images, postedto } = postData;
const handleChange = name => e => {
setPostData({ ...postData, [name]: e.target.value, images: e.target.files });
};
const createPost = async e => {
e.preventDefault();
await addPost(postData, setUploadPercentage);
};
从那里开始我的操作 addPost;在这个函数上我调用了两个 API 路由:
// @route POST api/v1/posts
// @description Add post
// @access Private
// @task DONE
export const addPost = (formData, setUploadPercentage) => async dispatch => {
try {
// ATTACH FILES
let fileKeys = [];
for(let file of formData.images) {
const uploadConfig = await axios.get(`${API}/api/v1/uploads/getS3url?type=${file.type}`);
await axios.put(uploadConfig.data.url, file, {
headers: {
'Content-Type': file.type
}
});
fileKeys.push(uploadConfig.data.key);
}
console.log(fileKeys);
// INSERT NEW BLOG
const config = {
headers: {
'Content-Type': 'multipart/form-data; application/json'
},
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
// Clear percentage
setTimeout(() => setUploadPercentage(0), 10000);
}
};
formData.images = fileKeys;
const res = await axios.post(`${API}/api/v1/posts`, formData, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};
我的 getS3url 函数看起来完全像这样:
exports.uploadFile = asyncHandler(async (req, res, next) => {
const { type } = req.query;
const fileExtension = type.substring(type.indexOf('/') + 1);
const key = `${process.env.WEBSITE_NAME}-${req.user._id}-${
req.user.email
}-${Date.now().toString()}.${fileExtension}`;
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: key,
ContentType: type
};
s3.getSignedUrl(`putObject`, params, (err, url) => {
if (err) {
return next(
new ErrorResponse(
`There was an error with the files being uploaded`,
500
)
);
}
return res.status(201).json({ success: true, key: url });
});
});
我想指出,每个 post 可能有多个图像文件,函数应该 return 为每个文件签名 URL;假设我上传了两个文件,然后我应该检索两个 URLS 以便将它们附加到我的 post.
我确定我管理状态以提交数据的方式没有任何问题,因为它总是 return 我在 console.log(postData)
上使用时所期望的,甚至显示文件。
现在我假设问题出在我的操作上,尤其是 /// INSERT NEW BLOG
注释之前的代码,因为当我 console.log(fileKeys)
什么都没有 returned,甚至 error/undefined/null.....我什么都不是!
我的 uploadFile 在与单个文件一起使用时工作正常....不是真的,因为是的,它 return 是 'supposed' 上传文件的 URL 但是当我进入我的 AWS console/bucket,什么都没有..但那是它自己的 post。
我需要什么帮助?
好吧,我正在尝试使用签名 URL 将 one/multiple 文件上传到我的 AWS,并将它们作为字符串 return 附加到我的 post 中。我的动作文件有问题吗?
谢谢!!
对于我的情况,我一直在遍历图像并生成带符号的 URLs 并返回它们,因为 s3 不支持一次用于多个文件的带符号 URL 选项。
最后我找到了自己的解决方案,这里是:
export const addPost = (formData, images, setUploadPercentage) => async dispatch => {
try {
let fileKeys = [];
for(let i = 0; i < images.length; i++) {
/// STEP 3
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const uploadConfig = await api.get(`/uploads/getS3url?name=${images[i].name}&type=${images[i].type}&size=${images[i].size}`);
// STEP 1
delete api.defaults.headers.common['Authorization'];
await api.put(uploadConfig.data.postURL, images[i], {
headers: {
'Content-Type': images[i].type
}
});
fileKeys.push(uploadConfig.data.getURL);
}
// INSERT NEW BLOG
const config = {
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
setTimeout(() => setUploadPercentage(0), 10000);
}
};
// STEP 2
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const res = await api.post(`/posts`, {...formData, images: fileKeys}, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};