一文看懂MsgPack与Alova的完美搭配

859 阅读6分钟

1. 什么是MsgPack

MsgPack(MessagePack)是一种高效的二进制序列化格式,类似于JSON,但更小、更快、更简单。它允许你像使用JSON那样轻松地交换数据,但是序列化后的数据体积更小,解析速度更快。MsgPack由一个C语言库提供支持,并且有多种编程语言的实现。

2. Msgpack与JSON有什么区别

  1. 数据大小:MsgPack 编码的数据通常比 JSON 小,这意味着在网络传输和存储时能更有效率。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。这种紧凑的二进制格式使得 MsgPack 在数据交换时更加高效,尤其是在处理大量数据时。

  2. 速度:在序列化和反序列化操作上,MsgPack 通常比 JSON 更快。这是因为二进制格式的处理通常比文本格式更快。在数据量较小的情况下,MsgPack 的效率可能不如 JSON,但在数据量较大时,MsgPack 的效率就远大于 JSON。

  3. 二进制格式:作为一个二进制格式,MsgPack 处理二进制数据要比 JSON 更自然和高效,而无需转换或使用特殊编码。这使得 MsgPack 在处理二进制数据时更加高效。

  4. 跨语言支持:尽管 JSON 同样拥有广泛的语言支持,MsgPack 通过其官方和社区支持的库,也在多种语言环境中得到了良好的应用。

  5. 适用场景:MsgPack 适用于对速度和数据大小有较高要求的场景,如网络通信、数据缓存和文件存储。在微服务或分布式系统中,使用 MsgPack 可以减少传输的数据量,加快交换速度。

  6. 性能测试:在一些性能测试中,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后的对比结果:

image.png

可以看到,这个简单的JSON对象,转换为MsgPack以后,数据大小只有原来的一半左右。

在处理大数据时,这个数据大小对比会更加的明显。

5. 与Alova结合使用

接下来,我们通过一个小案例,来完成MsgPack的一次实战演练:

5-1. 创建一个MsgPack的接口

ApiFox上创建一个mock的接口:

image.png 注意:接口返回的数据格式为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中我们通过AlovauseRequesthook自动发起接口请求,然后进行展示:

import { useRequest } from 'alova/client';
import { getMsgPack } from '@/API'

const { data } = useRequest(getMsgPack)
  <section>{{ data }}</section>

本地允许dev命令,查看最后的效果:

image.png 通过Network可以看到,接口返回的是MsgPack的数据格式,最终页面上成功转换为JSON格式。

image.png 数据量也只有JSON格式的一半。

6.源码分享

以上源码都已经提交到Gitee上,有需要的可以自取。