深入解析阿里云对象存储服务(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 就好了。

相关推荐
流烟默2 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_8572979112 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_22 分钟前
meta标签作用/SEO优化
前端·javascript·html
Ink31 分钟前
从底层看 path.resolve 实现
前端·node.js
金灰32 分钟前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
茶卡盐佑星_35 分钟前
说说你对es6中promise的理解?
前端·ecmascript·es6
Манго нектар1 小时前
JavaScript for循环语句
开发语言·前端·javascript
蒲公英10011 小时前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
天涯学馆2 小时前
Deno与Secure TypeScript:安全的后端开发
前端·typescript·deno
以对_2 小时前
uview表单校验不生效问题
前端·uni-app