前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己通过COS/CDN实现的Precompression

自己通过COS/CDN实现的Precompression

原创
作者头像
黄希彤
修改2023-02-23 12:25:34
9080
修改2023-02-23 12:25:34
举报
文章被收录于专栏:黄希彤的专栏黄希彤的专栏

想把很多文本形式的数据放在COS上通过CDN发布。CDN自带有gzip/brotli压缩功能,确实省下了很多不必要的流量。

但是通过cdn的压缩功能来发布,要求cos上保存压缩前的数据,cdn在回源后再就地压缩。这样一方面给COS带来了很多不必要的存储(不过COS存储并不贵,这倒不是大问题);另一方面数据要用原始形态上传到COS,这样多传了好几倍的数据,上传时间也就延长了好几倍,这就有点讨厌了。

CDN的工作基本类似于Nginx,在Nginx上这个问题有很简单的解决方案是Gzip-Precompression,也就是直接把原始数据gzip压缩上传到服务器,服务器在收到支持gzip的http请求后检查到已经存在了对应的gz文件就可以直接把预压缩的数据吐出去。而CDN没有实现这个功能。那就只能自力更生了。

step 1 把数据gzip压缩后保存到COS上:

代码语言:javascript
复制
const fs = require("fs"),
	zlib = require('zlib'),
	key = require('./key'),
	COS = require('cos-nodejs-sdk-v5'),
	cos = new COS(key.Secret);
async function zipFile2Cos(filePath, cosPath) {
	return new Promise((res, rej) => {
		cos.putObject({
			Bucket: key.cosInfo.Bucket,
			Region: key.cosInfo.Region,
			Key: cosPath,
			StorageClass: 'STANDARD',
			Body: fs.createReadStream(filePath).pipe(zlib.createGzip())
		}, function(err, data) {
			if (err) {
				rej(err);
			} else {
				res(data)
			}
		});
	})
}

cosPath建议使用.gz后缀,比较规范。这里因为本地已经有了文件,就直接吧文件流pipe给zlib变成压缩流然后交给COS的SDK上传,用stream方式这样处理数据可以节省大量的内存。一样的道理,如果要在数据生产程序里面上传的话可以自己包装一个可读流来做。在处理大块的数据上吃过内存溢出苦头的人都懂。

2 网页端通过cdn下载到预压缩的数据以后,用fflate来做前端解压。

代码语言:javascript
复制
<script src="https://cdn.jsdelivr.net/npm/fflate@0.7.4/umd/index.js"></script>
<script>
async function unzip(path){
		return await fetch(path).then(res=>res.arrayBuffer()).then(arrayBuffer => {
		const decompress = fflate.decompressSync(new Uint8Array(arrayBuffer));
		return fflate.strFromU8(decompress);
	})
}
unzip(gzFilePath).then(data=>console.log("Unzip:",data.length))
</script>

一样的,处理大块的数据的时候用流式的方式处理更快并且更省内存,不过fetch的流( getReader.read() )读取到最后会得到一个 undefined 的 chunk,而fflate的解压流 ( fflate.Decompress )不支持push undefinde进去,要转换成空串:

代码语言:javascript
复制
async function streamUnzip(path){
	let result = [];
	const utfDecode = new fflate.DecodeUTF8((data, final) => {
	  result.push(data);
	});
	const dcmpStrm = new fflate.Decompress((chunk, final) => {
	  utfDecode.push(chunk, final);
	});
	await fetch(path).then(res=>res.body.getReader()).then(async reader=>{
		while(true){
			let {done, value} = await reader.read();
			dcmpStrm.push(value || "",done);
			if(done) break;
		}
	})
	return result.join("")
}
streamUnzip(gzFilePath).then(data=>console.log("streamUnzip:",data.length))

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档