[英]Unable to upload image file to s3 from React with Node presigned url
我正在尝试将图像文件上传到 AWS S3 存储桶。 我正在使用 Node/Express 生成预签名的 URL 以将所述图像从 React 前端直接上传到 s3。 问题是我能够将文件作为文件上传(与本地 PC 上的大小相同),但它没有文件扩展名。 也就是说,它只有带符号的字符,例如9c9743b9-4dd7-4afa-af06-c060fb0fb175
文件类型,而不是9c9743b9-4dd7-4afa-af06-c060fb0fb175.png
文件类型为 png
这是我到目前为止所尝试的简短片段
后端
// My controller
try {
const payload = await AwsS3Service.getSignedUrlService();
res.status(200).send({
success: true,
data: payload
});
...
const s3 = new aws.S3({
region: config.awsS3.region,
accessKeyId: config.awsS3.accessKeyId,
secretAccessKey: config.awsS3.secretAccessKey,
signatureVersion: config.awsS3.signatureVersion
})
const getSignedUrlService = async () => {
const imageName = crypto.randomUUID()
const params = ({
Bucket: config.awsS3.bucketName,
Key: imageName,
Expires: 120 // in sec
})
const uploadUrl = await s3.getSignedUrlPromise('putObject', params)
return uploadUrl
}
前端
const [final, setFinal] = useState<FileList | any>('')
const [img, setImg] = useState<typeof formState.file>(null)
const handleImageChange = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files && e.target.files[0]
if (e.target.files) {
setFinal(e.target.files[0]!)
}
const { type, name } = file as File
setImgName(name)
setImgType(type)
const fileReader = new FileReader()
fileReader.onload = (e) => {
setImg(e.target?.result)
}
fileReader.readAsDataURL(file as Blob)
}
const handleFormSubmit: SubmitHandler<IImage> = async (data: IImage) => {
try {
const signedUrl = await axios({ method: 'GET', url: `${config.API_URL}/awss3` })
const formData = new FormData()
formData.append('file', final[0])
const resUpload = await fetch(`${signedUrl.data.data}`, {
method: 'PUT',
headers: { 'Content-Type': 'multipart/form-data' },
body: final
})
if (resUpload.status === 200) {
// redirect
}
} catch(err: any) {
alert(`An error occured. ${err.message}`)
}
}
return (
<form onSubmit={e => e.preventDefault()}>
<Stack>
<Box>
<InputLabel htmlFor='imgfile'>Image File</InputLabel>
<picture>
{ img
? <img src={img} alt='Image preview' height={90} width={160} />
: <Box sx={{ height: 90, width: 160, backgroundColor: '#555' }}></Box>
}
</picture>
<input type='file' accept='image/*' id='imgfile' name='imgFile' onChange={handleImageChange} />
</Box>
</Stack>
<Button type='submit' onClick={handleSubmit(handleFormSubmit)}>
Submit
</Button>
</form>
)
我已经有一段时间无法解决这个问题了。 任何帮助深表感谢。 感谢您阅读。
将此作为自我回答发布,以防万一有人感兴趣。
我设法解决了这个问题,方法是在将签名请求改为 POST 请求时添加文件名、类型和扩展名,并将文件名和文件类型附加到请求正文中。
// Frontend
const signedUrl = await axios({
method: 'POST',
url: `${config.API_URL}/awss3`,
headers: { 'Content-Type': 'application/json' },
data: { name: imgName, type: imgType }
})
并将它们添加到Key
中
// Backend
const getSignedUrlService = async (name, type) => {
// name and type from req.body
const imageName = crypto.randomUUID() + '-' + name
const params = ({
Bucket: config.awsS3.bucketName,
Key: imageName,
ContentType: type,
Expires: 120 // in sec
})
const uploadUrl = await s3.getSignedUrlPromise('putObject', params)
return uploadUrl
}
感谢所有帮助过的人
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.