前言
现在的文件上传,一般都会把文件上传到oss对象存储中,很少会把资源存在我们自己的业务服务端。这么做的优势主要有以下几点:
- 海量存储无上限:单 Bucket 支持千亿级文件存储,容量可随业务增长自动扩展,解决自建服务器的存储容量瓶颈。
- 全球访问低延迟:结合 CDN 的节点缓存,用户无论身处全球何地,均可快速获取资源,而自建方案需部署多地机房,成本高昂且技术复杂;
对象存储
-
我们电脑的文件存储方式一般都是 目录+文件:
-
oss 的存储方式如下:
采用桶的概念来进行存储,一个桶就是一个 Bucket,每个桶里面可以存储很多文件。
上传
想要把文件上传到oss,有以下几种方式:
- 直接通过oss控制台上传
- 前端代码写死sts的令牌、密钥(一般不建议这么做:令牌、密钥放在代码里面,容易被窃取)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<input id="file" type="file" />
<button id="upload">上传</button>
<script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.18.0.min.js"></script>
<script>
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
region: "yourRegion",
authorizationV4: true,
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: "yourAccessKeyId",
accessKeySecret: "yourAccessKeySecret",
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: "yourSecurityToken",
// 填写Bucket名称。
bucket: "examplebucket",
});
// 从输入框获取file对象,例如<input type="file" id="file" />。
let data;
// 创建并填写Blob数据。
//const data = new Blob(['Hello OSS']);
// 创建并填写OSS Buffer内容。
//const data = new OSS.Buffer(['Hello OSS']);
const upload = document.getElementById("upload");
async function putObject(data) {
try {
// 填写Object完整路径。Object完整路径中不能包含Bucket名称。
// 您可以通过自定义文件名(例如exampleobject.txt)或文件完整路径(例如exampledir/exampleobject.txt)的形式实现将数据上传到当前Bucket或Bucket中的指定目录。
// data对象可以自定义为file对象、Blob数据或者OSS Buffer。
const options = {
meta: { temp: "demo" },
mime: "json",
headers: { "Content-Type": "text/plain" },
};
const result = await client.put("examplefile.txt", data, options);
console.log(result);
} catch (e) {
console.log(e);
}
}
upload.addEventListener("click", () => {
const data = file.files[0];
putObject(data);
});
</script>
</body>
</html>
- 前端请求服务端接口,服务端下发认证密钥(安全性更好,实际开发也会这么使用)
服务端下发授权签名、前端拿到签名后把文件上传到oss。
- 创建 oss-signature-demo 目录,进入该目录
mkdir oss-demo
cd oss-demo
- 分别创建前后端代码目录
mkdir browser
mkdir service
- 进入 service 目录,安装依赖
cd service
npm init -y
npm install ali-oss cors express
- 创建 src/index.js文件,编写核心逻辑代码
mkdir src
touch src/index.js
const express = require('express');
const OSS = require('ali-oss');
const cors = require('cors');
const app = express();
// 添加 CORS 中间件
app.use(cors());
const config = {
// 填入你阿里云的accessKeyId和accessKeySecret
accessKeyId: '',
accessKeySecret: '',
// 填入你阿里云的bucket
bucket: '',
}
const client = new OSS (config);
app.get('/api/oss/signature',async (req, res) => {
try {
const date = new Date();
// 设置签名的有效期,单位为秒。
date.setSeconds(date.getSeconds() + 3600);
const policy = {
expiration: date.toISOString(),
conditions: [
// 设置上传文件的大小限制。
["content-length-range", 0, 1048576000],
// 限制可上传的Bucket。
{ bucket: client.options.bucket },
],
};
const formData = await client.calculatePostSignature(policy);
const host = `http://${config.bucket}.${
(await client.getBucketLocation()).location
}.aliyuncs.com`.toString();
const params = {
policy: formData.policy,
signature: formData.Signature,
ossAccessKeyId: formData.OSSAccessKeyId,
host,
};
res.json(params);
} catch (error) {
console.log(error);
res.status(500).json({ error: 'Failed to generate OSS signature' });
}
});
// 设置端口
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
node src/index.js
此时,服务端接口已经跑起来了。接下来编写前端上传逻辑:
- 进入前端目录,创建index.html文件
cd ..
cd browser
mkdir index.html
- index.html 代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>上传文件到OSS</title>
</head>
<body>
<div class="container">
<form>
<div class="mb-3">
<label for="file" class="form-label">选择文件</label>
<input
type="file"
class="form-control"
id="file"
name="file"
required
/>
</div>
<button type="submit" class="btn btn-primary">上传</button>
</form>
</div>
<script type="text/javascript">
const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
form.addEventListener("submit", (event) => {
event.preventDefault();
let file = fileInput.files[0];
let filename = fileInput.files[0].name;
fetch("http://localhost:3000/api/oss/signature", {
method: "GET",
headers: {
Accept: "application/json",
},
})
.then((response) => response.json())
.then((data) => {
const formData = new FormData();
formData.append("name", filename);
formData.append("policy", data.policy);
formData.append("OSSAccessKeyId", data.ossAccessKeyId);
formData.append("success_action_status", "200");
formData.append("signature", data.signature);
formData.append("key", filename);
// file必须为最后一个表单域,除file以外的其他表单域无顺序要求。
formData.append("file", file);
fetch(data.host, { method: "POST", body: formData }).then((res) => {
console.log(res);
alert("文件已上传");
});
})
.catch((error) => {
console.log(
"Error occurred while getting OSS upload parameters:",
error
);
});
});
</script>
</body>
</html>
效果
总结
我们先简单介绍了下oss存储的优势以及特征,接着通过案例介绍了如何把文件上传到oss中,主要有3种方式:
- 直接通过oss控制台上传
- 前端代码写死sts的令牌、密钥(一般不建议这么做:令牌、密钥放在代码里面,容易被窃取)
- 前端请求服务端接口,服务端下发认证密钥(安全性更好,实际开发也会这么使用)
代码已经上传到:github