【发布时间】:2022-01-26 03:12:03
【问题描述】:
我正在使用 axios 将音频文件上传到 AWS s3 存储桶。
工作流程是:React => AWS API Gateway => Lambda。
这是生成 S3 预签名 URL 的后端 Lambda 代码:
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(AUDIO_S3_BUCKET)
.key(objectKey)
.contentType("audio/mpeg")
.build();
PutObjectPresignRequest putObjectPresignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(10))
.putObjectRequest(putObjectRequest)
.build();
PresignedPutObjectRequest presignedPutObjectRequest = s3Presigner.presignPutObject(putObjectPresignRequest);
AwsProxyResponse awsProxyResponse = new AwsProxyResponse();
awsProxyResponse.setStatusCode(HttpStatus.SC_OK);
awsProxyResponse.setBody(
GetS3PresignedUrlResponse.builder()
.s3PresignedUrl(presignedPutObjectRequest.url().toString())
.build().toString());
return awsProxyResponse;
这里是创建bucket的java代码:
private void setBucketCorsSettings(@NonNull final String bucketName) {
s3Client.putBucketCors(PutBucketCorsRequest.builder()
.bucket(bucketName)
.corsConfiguration(CORSConfiguration.builder()
.corsRules(CORSRule.builder()
.allowedHeaders("*")
.allowedMethods("GET", "PUT", "POST")
.allowedOrigins("*") // TODO: Replace with domain name
.exposeHeaders("ETag")
.maxAgeSeconds(3600)
.build())
.build())
.build());
log.info("Set bucket CORS settings successfully for bucketName={}.", bucketName);
}
在我的前端,这里是尝试上传文件的部分:
const uploadFile = (s3PresignedUrl: string, file: File) => {
let formData = new FormData();
formData.append("file", file);
formData.append('Content-Type', file.type);
const config = {
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
//"Content-Type": file.type,
},
onUploadProgress: (progressEvent: { loaded: any; total: any; }) => {
const { loaded, total } = progressEvent;
let percent = Math.floor((loaded * 100) / total);
if (percent < 100) {
setUploadPercentage(percent);
}
},
cancelToken: new axios.CancelToken(
cancel => (cancelFileUpload.current = cancel)
)
};
axios(
{
method: 'post',
url: s3PresignedUrl,
data: formData,
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
}
}
)
.then(res => {
console.log(res);
setUploadPercentage(100);
setTimeout(() => {
setUploadPercentage(0);
}, 1000);
})
.catch(err => {
console.log(err);
if (axios.isCancel(err)) {
alert(err.message);
}
setUploadPercentage(0);
});
};
但是,当尝试上传文件时,它返回 403 错误。
如果我使用 fetch 而不是 axios 并且它可以工作,就像这样:
export async function putToS3(presignedUrl: string, fileObject: any) {
const requestOptions = {
method: "PUT",
headers: {
"Content-Type": fileObject.type,
},
body: fileObject,
};
//console.log(presignedUrl);
const response = await fetch(presignedUrl, requestOptions);
//console.log(response);
return await response;
}
putToS3(getPresignedUrlResponse['s3PresignedUrl'], values.selectdFile).then(
(putToS3Response) => {
console.log(putToS3Response);
Toast("Success!!", "File has been uploaded.", "success");
}
);
在我看来,这两者之间的唯一区别是:使用fetch时,请求的Content-Type标头是Content-Type: audio/mpeg,但使用axios时,它是Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryClLJS3r5Xetv3rN7 。
如何使它与 axios 一起工作?我正在切换到 axios,因为它能够监控请求进度,因为我想显示一个上传进度条。
我关注了这个博客,但不确定我错过了什么:https://bobbyhadz.com/blog/aws-s3-presigned-url-react
【问题讨论】:
-
您在 axios 上使用
method: 'post',您可能想改用put。 -
我试过了,还是不行。
标签: reactjs amazon-web-services amazon-s3 axios