最近使用AWS S3进行预签名URL上传文件开发,预签名URL上传好处是文件不需要经过后端中转,直接前端上传文件到公有云AWS的对象存储。前端同事遇到了点问题,上传不成功。我看了下主要集中在2个方向,一是自己定义了form数据,然后后端是没有定义相关meta-data的,导致上传的整个form被当做了文件内容数据。二是后端签名URL生成的时候content-type的定义和前端定义的不一致。以下是后端和前端的代码:
AWS预签名生成示例代码,使用software.amazon.awssdk s3依赖:
public String getUploadURL(String objectName) {
URL url = s3Presigner.presignPutObject(x ->
x.signatureDuration(Duration.ofMinutes(10))
.putObjectRequest(y ->
y.bucket(ossProperties.getBucketName())
.key(objectName)
.build()).build()).url();
return url.toString();
}
AWS上传文件前端代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AWS S3 JS Integration</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="application/javascript">
function upload() {
fetch('http://127.0.0.1:8080/api/upload/url', {
method: 'GET',
headers: {'Accept': 'application/json'}
}).then(resp => resp.json())
.then(data => {
//创建文件流
const fileInput = document.querySelector('#fetchFile');
const fileStream = fileInput.files[0];
//响应的预签名URL放在了response的data属性里,所以是resp.data.uploadUrl,下同
console.log(data.data);
// 发送请求
fetch(data.data.uploadUrl, {
method: 'PUT',
body: fileStream
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log('Error:', error))
})
}
function uploadAxios() {
axios.get('http://127.0.0.1:8080/api/upload/url')
.then(function (response) {
const data = response.data;
console.log(data.data);
//创建文件流
const fileInput = document.querySelector('#axiosFile');
const fileStream = fileInput.files[0];
axios({
method: "put",
url: data.data.uploadUrl,
//重点,直接将原始二进制流赋给data
data: fileStream,
headers: {
//必须设置成流
"Content-Type": "application/octet-stream",
},
//必须设置
responseType: "blob",
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
})
.catch(function (error) {
//请求失败处理
console.log(error);
});
}
function uploadAxios2() {
axios.get('http://127.0.0.1:8080/api/upload/url')
.then(function (response) {
const data = response.data;
console.log(data.data);
//创建文件流
const fileInput = document.querySelector('#axiosFile');
const fileStream = fileInput.files[0];
//转换形式
const reader = new FileReader();
reader.readAsArrayBuffer(fileStream);
//上传图片
reader.onload = () => {
//上传图片接口 data.data.uploadUrl:上传图片地址 修改请求头
axios.put(data.data.uploadUrl, reader.result, {header: {"Content-Type": "multipart/form-data"}})
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
};
})
.catch(function (error) {
//请求失败处理
console.log(error);
});
}
</script>
</head>
<body>
<p>fetch上传</p><input id="fetchFile" type="file" onchange="upload()" placeholder="fetch上传">
<br/>
<br/>
<br/>
<p>axios上传</p><input id="axiosFile" type="file" onchange="uploadAxios()" placeholder="axios上传">
</body>
</html>