深入解析阿里云对象存储服务(OSS、Node)

对象存储服务(OSS)介绍

文件上传是常见的网络需求,通常我们不会将文件直接上传到应用服务器,因为单台服务器的存储空间有限,不易扩展。

为此,我们通常使用对象存储服务(Object Storage Service,简称OSS)来完成文件的上传和下载。例如,阿里云提供的 OSS 服务就是这样一个平台。

OSS 存储和检索非结构化数据和元数据对象(如文档、图片、视频等)。

本地存储和 OSS 存储结构对比

本地文件存储:采用目录和文件的组织方式。

OSS 存储结构:

  • OSS 中的对象是存储的基本单元,每个对象包含数据、元数据和唯一标识符。
  • 桶(Bucket)是用于组织对象的容器,每个桶内可以存储无数个对象,并且可以通过 RESTful API 接口进行操作。
  • 值得注意的是,虽然阿里云 OSS 的控制台显示对象存储没有目录层级结构,但它实际上是通过元数据部分模拟实现了目录层级,使得用户可以使用"标签"来检索文件。

阿里云的其他存储服务

除了对象存储OSS,阿里云还提供文件存储和块存储服务。

文件存储具有目录层次结构,可以上传和下载文件,但存储容量有限。

块存储则是将整块磁盘提供给你,需要自行格式化,存储容量同样有限。

对象存储OSS则是分布式实现的 key-value 存储,存储容量几乎是无限的。

绝大多数情况下,我们都是用 OSS 对象存储。

OSS 服务购买

我们买个阿里云的 OSS 服务

我买了 40G 的 OSS 国内通用资源包,花了 5 块钱。

然后我们创建个 Bucket(桶):

在北京创建了一个 Bucket,文件就会存储在那里的服务器上。

可以设置为公共读,也可以设置为私有,需要身份验证才能访问。

如果文件仅存储在北京的服务器上,那么在其他地区访问是否会受到速度的影响?

这就是 CDN(内容分发网络)的用武之地。通过 CDN,用户访问特定域名时,会被引导至最近的缓存服务器,从而加速文件的访问速度。

控制台上传文件

创建 Bucket 之后,我们就可以上传文件了:


上传完之后在文件列表就可以看到这个文件了:

生产环境下我们不会直接用 OSS 的 URL 访问,而是会开启 CDN:

  • 当用户通过网站域名请求文件时,请求会被 CDN 服务接收。
  • CDN 会根据用户的地理位置,将请求重定向到最近的缓存服务器。
  • 如果这个服务器上已经缓存了请求的文件,那么文件将直接从该服务器提供给用户,从而减少了数据传输的延迟。
  • 如果缓存服务器上没有文件,它会从原始位置(即 OSS 服务)获取文件,并将其缓存以备后续请求使用。

Node 上传下载 OSS 图片

代码准备

bash 复制代码
mkdir oss-test
cd oss-test
npm init -y

安装用到的包:

bash 复制代码
npm install ali-oss

代码:

javascript 复制代码
const OSS = require('ali-oss')

const client = new OSS({
    region: 'oss-cn-beijing',
    bucket: 'yun-667',
    accessKeyId: '',
    accessKeySecret: '',
});

async function put () {
  try {
    const result = await client.put('yun.png', './avatar.png');
    console.log(result);
  } catch (e) {
    console.log(e);
  }
}

put();

new OSS 的时候有几个选项需要获取。

获取 region

region 在概览可以看到:

获取 accessKey

这里的 accessKeyId 和 acessKeySecret 是什么呢?

阿里云的安全策略建议使用 AccessKey(包括 AccessKeyId 和 AccessKeySecret )进行身份认证,而不是直接使用用户名和密码。

为了进一步减少安全风险,建议使用 RAM(Resource Access Management)子用户的方式生成 AccessKey,这样可以最小化权限。

我们创建个 accesKey:




创建完成后,就可以拿到 accesKeyId 和 accessKeySecret。

设置访问控制


新增一个授权:

把 OSS 的管理和读取权限给这个子用户:

运行上传文件代码

node 运行下:

这时候就上传成功了。
阿里云的大文件分片上传直接看文档就行了。

下载图片


OSS 上传方案

在实际应用中,我们可以选择让客户端直接将文件上传至 OSS:

也可以先上传至应用服务器,再由应用服务器转发至 OSS。

直接上传可以节省应用服务器的流量,但增加了 accessKey 泄露的风险

有没有什么两全其美的办法?

阿里云的文档里也提到了这个问题。

它给出的解决方案就是生成一个临时的签名来用。

代码是这样的:

javascript 复制代码
const OSS = require('ali-oss');

async function main() {
	const config = {
		region: '',
		bucket: '',
		accessKeyId: '',
		accessKeySecret: '',
	};

	const client = new OSS(config);

	const date = new Date();

	date.setDate(date.getDate() + 1);

	const res = client.calculatePostSignature({
		expiration: date.toISOString(),
		conditions: [
			['content-length-range', 0, 1048576000], //设置上传文件的大小限制。
		],
	});

	console.log(res);

	const location = await client.getBucketLocation();

	const host = `http://${config.bucket}.${location.location}.aliyuncs.com`;

	console.log(host);
}

main();

获取到了临时凭证的信息:

这样就能在网页里用这些来上传文件到 OSS 了:

创建个 index.html:

html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<script src="https://unpkg.com/axios@1.6.5/dist/axios.min.js"></script>
	</head>
	<body>
		<input id="fileInput" type="file" />

		<script>
			const fileInput = document.getElementById('fileInput');

			async function getOSSInfo() {
				// 下面的信息可以通过请求服务器获取
				return {
					OSSAccessKeyId: '',
					Signature: '',
					policy: '',
					host: '',
				};
			}

			fileInput.onchange = async () => {
				const file = fileInput.files[0];

				const ossInfo = await getOSSInfo();

				const formdata = new FormData();

				formdata.append('key', file.name);
				formdata.append('OSSAccessKeyId', ossInfo.OSSAccessKeyId);
				formdata.append('policy', ossInfo.policy);
				formdata.append('signature', ossInfo.Signature);
				formdata.append('success_action_status', '200');
				formdata.append('file', file);

				const res = await axios.post(ossInfo.host, formdata);
				if (res.status === 200) {
					const img = document.createElement('img');
					img.src = ossInfo.host + '/' + file.name;
					document.body.append(img);

					alert('上传成功');
				}
			};
		</script>
	</body>
</html>

跑个静态服务器:

html 复制代码
npx http-server .

我们需要在控制台开启下跨域:

上传文件:

上传成功了。

控制台文件列表也可以看到这个文件:

这就是完美的 OSS 上传方案。

服务端用 RAM 子用户的 accessKey 来生成临时签名,然后返回给客户端,客户端用这个来直传文件到 OSS。

因为临时的签名过期时间很短,我们设置的是一天,所以暴露的风险也不大。

这样服务端就根本没有接受文件的压力,只要等客户端上传完之后,带上 URL 就好了。

相关推荐
gnip19 分钟前
vite和webpack打包结构控制
前端·javascript
excel40 分钟前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国1 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼1 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy1 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT1 小时前
promise & async await总结
前端
Jerry说前后端1 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天1 小时前
A12预装app
linux·服务器·前端
7723892 小时前
解决 Microsoft Edge 显示“由你的组织管理”问题
前端·microsoft·edge
烛阴2 小时前
前端必会:如何创建一个可随时取消的定时器
前端·javascript·typescript