1. 什么是MsgPack
MsgPack(MessagePack)是一种高效的二进制序列化格式,类似于JSON,但更小、更快、更简单。它允许你像使用JSON那样轻松地交换数据,但是序列化后的数据体积更小,解析速度更快。MsgPack由一个C语言库提供支持,并且有多种编程语言的实现。
2. Msgpack与JSON有什么区别
-
数据大小:MsgPack 编码的数据通常比 JSON 小,这意味着在网络传输和存储时能更有效率。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。这种紧凑的二进制格式使得 MsgPack 在数据交换时更加高效,尤其是在处理大量数据时。 -
速度:在序列化和反序列化操作上,MsgPack 通常比 JSON 更快。这是因为二进制格式的处理通常比文本格式更快。在数据量较小的情况下,MsgPack 的效率可能不如 JSON,但在数据量较大时,MsgPack 的效率就远大于 JSON。 -
二进制格式:作为一个二进制格式,MsgPack 处理二进制数据要比 JSON 更自然和高效,而无需转换或使用特殊编码。这使得 MsgPack 在处理二进制数据时更加高效。 -
跨语言支持:尽管 JSON 同样拥有广泛的语言支持,MsgPack 通过其官方和社区支持的库,也在多种语言环境中得到了良好的应用。 -
适用场景:MsgPack 适用于对速度和数据大小有较高要求的场景,如网络通信、数据缓存和文件存储。在微服务或分布式系统中,使用 MsgPack 可以减少传输的数据量,加快交换速度。 -
性能测试:在一些性能测试中,MsgPack 显示出了比 JSON 更高的效率。例如,对于大量数据的处理,MsgPack 的压缩和解压速度更快,且处理后的数据大小与 JSON 相比有显著的减少。
3. MsgPack工作原理解析
我们通过一个简单的例子来说明MsgPack的工作原理。假设我们有一个简单的JSON对象,我们想将其序列化成MsgPack格式。
3-1. JSON对象示例
假设我们有以下JSON对象:
{
"name": "John Doe",
"age": 30,
"is_student": false,
"scores": [88, 92, 85],
"address": {
"street": "1234 Main St",
"city": "Anytown",
"zip": "12345"
}
}
3-2. 序列化成MsgPack
将上述JSON对象序列化成MsgPack格式,我们首先需要理解MsgPack的编码规则。MsgPack使用不同的字节来表示不同类型的数据:
0x81表示一个Map(键值对)的开始,后面跟着键值对的数量。0xa3表示一个字符串的长度为3。0xa5表示一个字符串的长度为5。0xc0表示一个null值。0xc2表示一个false值。0xc3表示一个true值。0xca表示一个32位浮点数。0xcb表示一个64位浮点数。0xcc表示一个8位无符号整数。0xcd表示一个16位无符号整数。0xce表示一个32位无符号整数。0xcf表示一个64位无符号整数。
使用这些规则,上述JSON对象的MsgPack编码可能如下:
85 # Map with 5 key-value pairs
a4 name
a9 John Doe
a3 age
cd 30
a9 is_student
c2 # false
a6 scores
93 # Array with 3 elements
cc 88
cc 92
cc 85
a6 address
83 # Map with 3 key-value pairs
a5 street
a7 1234 Main St
a3 city
a6 Anytown
a3 zip
ce 12345
3-3. 解释
85表示后面跟着5个键值对。a4 name表示键 "name"。a9 John Doe表示值 "John Doe"。a3 age表示键 "age"。cd 30表示值 30。a9 is_student表示键 "is_student"。c2表示值 false。a6 scores表示键 "scores"。93表示后面跟着3个元素的数组。cc 88表示数组中的值 88。cc 92表示数组中的值 92。cc 85表示数组中的值 85。a6 address表示键 "address"。83表示后面跟着3个键值对。a5 street表示键 "street"。a7 1234 Main St表示值 "1234 Main St"。a3 city表示键 "city"。a6 Anytown表示值 "Anytown"。a3 zip表示键 "zip"。ce 12345表示值 12345。
这个序列化的MsgPack数据比原始的JSON数据更紧凑,且在解析时更高效。
4. 数据大小对比
在MsgPack官网上,提供了一个JSON与msgPack转换,以及数据大小对比的功能,我们来看一下对比上述JSON数据转换为MsgPack后的对比结果:
可以看到,这个简单的JSON对象,转换为MsgPack以后,数据大小只有原来的一半左右。
在处理大数据时,这个数据大小对比会更加的明显。
5. 与Alova结合使用
接下来,我们通过一个小案例,来完成MsgPack的一次实战演练:
5-1. 创建一个MsgPack的接口
在ApiFox上创建一个mock的接口:
注意:接口返回的数据格式为
MsgPack,同时对返回的字段数据进行一些mock。
5-2. 使用Alova发起请求
这里基于vue3快速创建一个实例项目,然后使用Alova3创建接口请求的方法:
import { createAlova } from 'alova'
import VueHook from 'alova/vue';
import adapterFetch from 'alova/fetch';
import { decode } from '@msgpack/msgpack';
const alova = createAlova({
baseURL: 'https://apifoxmock.com/m1/4992867-4651676-default', // APIFOX mock接口
statesHook: VueHook,
requestAdapter: adapterFetch(),
timeout: 20000,
responded: {
// 请求成功的拦截器
onSuccess: async (response: Response) => {
const arrayBuffer = await response.arrayBuffer()
const uint8Array = new Uint8Array(arrayBuffer)
// 将二进制数据转换为JSON
return decode(uint8Array)
}
}
})
// mock msgPack请求
export const getMsgPack = () => {
return alova.Get(`msg-pack`)
}
在创建的alova实例中,添加全局请求拦截器,然后读取响应的二进制数据,并通过@msgpack/msgpack官方包的decode方法,将其转换为JSON格式,供页面组件使用。
5-3. getMsgPack调用
在入口文件App.vue中我们通过Alova的useRequesthook自动发起接口请求,然后进行展示:
import { useRequest } from 'alova/client';
import { getMsgPack } from '@/API'
const { data } = useRequest(getMsgPack)
<section>{{ data }}</section>
本地允许dev命令,查看最后的效果:
通过Network可以看到,接口返回的是
MsgPack的数据格式,最终页面上成功转换为JSON格式。
数据量也只有JSON格式的一半。
6.源码分享
以上源码都已经提交到Gitee上,有需要的可以自取。