【解决方案】微信小程序如何使用 ProtoBuf 进行 WebSocket 通信

前言

故事背景

简单说下背景,项目中需要用 ProtoBuf 协议转换请求参数,并通过 WebSocket 进行双向通信。重点!一个是 web端(Vue3 + TS),一个是微信小程序端(原生 + JS)。

剧情发展

一开始,web端通过 ts-proto 这个库进行开发,问题倒是不大。将跑通的这部分代码进行 ts 转 js 之后挪用到微信小程序端的时候,奇奇怪怪的问题就出现了。

灵异事件(一)

问题描述

问题1: 发送文本消息(电脑上正常,手机上直接发送失败)

问题描述:
发送文本消息的情况,在电脑上,也就是微信开发者工具中的 模拟器 上,是可以正常通信的;但是在手机上,也就是预览的时候,发送文本是直接无法发送, 报错提示大致意思就是方法执行失败,可以很容易定位到在数据转换(encode)的这个过程有问题

问题截图:

(1)电脑端 - 正确:

模拟器-发送文本消息-正常

(2)手机端 - 报错:

手机端-发送文本消息-失败

问题2:发送语音消息(电脑能发但是服务端解析失败,手机上直接就发不了)

问题描述:
最离谱,也是最坑的事件来了。
当电脑端发送语音消息的时候,WS可以正常来回通信,但是服务端拿到的语音数据解析异常,导致语音文本识别失败,并且这段语音数据生成的url是无法播放的。
当手机端发送语音消息的时候,表现就和上面的发送文本消息一样,直接发送不出去,这个倒是可以接受,可以直接定位到前端数据转换(encode)的过程有问题。

问题截图:

(1)电脑端 - 发送成功,但是服务端获取到的语音数据是异常的,导致语音转文本失败:

电脑-发送语音-发成功但语音解析失败

(2)手机端 - 报错:

手机端-发语音-失败

解决方案

1、分析原因

通过在项目中 断点调试(或者 console.log) 的方法,可以很快定位到是 proto 文件生成的 JS 文件中的变量方法 encode 在小程序端无效。注意:这个方法在浏览器web页面上是可行的!所以,大概率是由于宿主环境不同导致转编译方法的一些内部依赖无效。毕竟,web端用的第三方库主要是针对浏览器环境的,并没有明确说支持微信端
回顾一下 web端项目引用的第三方库是 TS 版本的 protobuf —— ts-proto 那么以上的那个推测原因就更有可能了。

所以,第一步,在小程序端重新引用 JS 版本的 protobuf —— protobufjs

2、npm包介绍

这部分是最精彩的部分,所以单独拎出来,作为第二步讲解。

当我们用 protobufjs 这个库的时候,需要两样东西,一个是代码中需要引用的 protobuf 本人,一个是用来转换 xxx.proto 文件用的脚本命令 pbjs 也就是我下面截图中提到的 protobufjs-cli

当我们打开 protobufjs 这个使用教程的时候,会看到下面这个安装指引。

protobufjs-Installation

这里需要重点说明一下,之前只要执行 npm install protobufjs --save 这端安装脚本之后,就可以使用 pbjs 命令的,但是!改了!一切都变了!请看官方说明—— pbjs-for-javascript

pbjs-for-javascript

这里重点吐槽一下,上面截图中的 its own package 点过去还是个404页面!所以,这里我们只能通过 protobufjs 在安装指引中提到的 protobufjs-cli 联想推测应该指的就是这个库了!

protobuf.js-cli

3、具体步骤

综上所述,你要做的就是:

步骤一:安装 npm 包
  1. 在你的微信小程序项目中,终端打开,执行命令如下:
npm install protobufjs --save
  1. 打开你的电脑终端(这里我以mac为例),执行命令如下:
sudo npm install -g protobufjs-cli

安装完之后,可以执行一下 pbjs 是否可用,正常输出如下:
在这里插入图片描述

步骤二:转换 proto 文件为 js 文件

通过上面安装的库,我们继续使用 pbjs 命令来生成 xxx.proto 对应的 JS文件,例如我这个项目使用的命令如下:

pbjs -t static-module -w commonjs -o ./protobuf/proto/base.js ./protobuf/proto/base.proto

上面这行命令你要改的就是把 输入、输出的文件路径 改成自己项目的路径即可。具体的参数介绍,务必去官网 pbjs-for-javascript 学习了解一下,知其然,知其所以然!

步骤三:修改生成的 xxx.js 文件

通过 pbjs 生成的 JS文件 还没完事,还需要再改一下这份 JS文件 内部的一行代码,具体如下:
pbjs-生成的js文件

步骤四:使用生成的 xxx.js 文件

在我们的业务代码中使用通过 pbjs 生成的 JS文件 ,具体细节如下:

1、导入 protobuf 的方法
import方法
2、使用 protobuf 实例对象中的属性与方法(encode、decode这些)
encode方法

3、本来这部分是要放到 灵异事件2 去讲解引出的,为了确保上下文的完整性,这里直接交代结果了。
ArrayBuff转换

关键代码:

const _xxxArrayBuffer_ = Uint8Array.from(_xxxUint8Array_).buffer;

重点说明:

因为我们用的 protobuf 这个库是通过 Uint8Array 进行 encode 和 decode 等一些列操作的;但是!微信小程序 WebSocket通信 并不支持 Uint8Array 数据,所以我们需要在发起请求之前对数据进行一个转换处理——将 Uint8Array 转成普通的 ArrayBuffer !


截止目前,问题已经解决。下文将继续分享解决过程中遇到的问题,以及涉及到的知识点、参考资料。

灵异事件(二)

这里让我们回到上面 解决方案 / 具体步骤 / 步骤四:使用生成的 xxx.js 文件 当我们通过网上教程正确安装并使用 protobufjs 时,发现离谱的事情又来了!

问题描述

简言之,就是电脑上可以,手机上不行。

问题1:

发送文本消息的时候,电脑端的模拟器上是可行的,一切都正常;手机端发送 websocket 请求时报错,大致意思是不支持的数据类型(fail invalid data type)。

问题2:

发送语音消息的时候,电脑端的模拟器上是 半可行的 ,注意这是最坑爹的,因为这个表现直接误导了问题定位方向 。所谓的 半可行的 就是和上面的 灵异事件(一)/ 问题2:发送语音消息(电脑能发但是服务端解析失败,手机上直接就发不了) 一样,电脑端的模拟器上表现:请求是发出去了,但是服务端获取到的语音数据是异常的,无法播放、无法识别语音文本内容。手机端表现:和上面的问题1一致,也是 websocket 请求失败(fail invalid data type)。

问题截图

(1)电脑端 - 发送文本成功,截图如下:

电脑端-正常

(2)手机端 - websocket 请求失败,截图如下:

小程序端-异常

解决方案

上文中已经交代过了,所以这里知识将上面的内容复制粘贴了一下,不介意的话,可以再看一遍。

本来这部分是要放到 灵异事件2 去讲解引出的,为了确保上下文的完整性, 这里直接交代结果了。
ArrayBuff转换

关键代码:

const _xxxArrayBuffer_ = Uint8Array.from(_xxxUint8Array_).buffer;

重点说明:

因为我们用的 protobuf 这个库是通过 Uint8Array 进行 encode 和 decode 等一些列操作的;但是!微信小程序 WebSocket通信 并不支持 Uint8Array 数据,所以我们需要在发起请求之前对数据进行一个转换处理——将 Uint8Array 转成普通的 ArrayBuffer !


知识点

1、ArrayBuffer、Uint8Array

定义

ArrayBuffer 和 Uint8Array 是 JavaScript 中用于处理二进制数据的两种不同类型的数据结构。

关系

Uint8Array是一种TypedArray(类型化数组),它是基于ArrayBuffer对象来构建的。ArrayBuffer是一个数据存储区,表示一段固定长度的二进制数据,而Uint8Array提供了一种视图,用于以特定的格式(在Uint8Array的情况下是无符号 8 位整数)来访问和操作ArrayBuffer中的数据。

简单地说,ArrayBuffer是底层的数据存储,Uint8Array是操作和访问这些存储数据的一种方式,可以将ArrayBuffer看作是一块内存区域,而Uint8Array则是在这块内存区域上的一种数据解析和操作工具。

区别

1、操作数据的方式:

ArrayBuffer: 由于ArrayBuffer本身没有操作数据的方法,所以不能直接对其存储的数据进行读写操作。如果要操作ArrayBuffer中的数据,必须通过视图(如Uint8Array等类型化数组视图或者DataView)来进行。

Uint8Array: Uint8Array提供了丰富的数组方法来操作数据,因为它将数据视为数组。例如,可以使用索引来访问和修改元素,像uint8Array[0]= 25;这样的操作就可以将Uint8Array视图中的第一个元素(对应ArrayBuffer中的第一个字节)设置为 25。同时,它还支持数组的遍历方法,如forEach、map等。

2、用途:

ArrayBuffer: 常用于在底层存储二进制数据,比如从网络接收的文件数据、图像数据、音频数据等原始字节流。它是一种通用的、原始的数据存储机制,在涉及到与外部数据源进行二进制数据交互时非常有用。

Uint8Array: 适合处理字节级别的数据,比如对二进制数据进行按字节的操作、解析简单的二进制协议等。因为它将数据视为无符号 8 位整数数组,所以在处理字节操作频繁的场景(如加密算法中的字节处理、简单的文件格式解析等)下更加方便和直观。

2、Protobuf

定义

Protocol Buffers(简称 Protobuf)是 Google 开发的一种数据序列化格式,用于将结构化数据序列化和反序列化。它类似于XML或JSON,但更小、更快、也更简单。Protobuf的设计初衷是为了解决通信协议和数据存储格式的问题,使得在多种编程语言之间高效地交换结构化数据成为可能。

数据格式特点

1、高效性

空间效率高: Protobuf 序列化后的数据格式紧凑,相比其他文本格式(如 XML、JSON),在存储和传输时占用更少的空间。例如,对于包含相同信息的整数、字符串等数据,Protobuf 序列化后的字节数通常远小于 JSON 格式。

时间效率高: 序列化和反序列化速度快,因为 Protobuf 使用了二进制格式,并且对数据的编码和解码进行了优化。在处理大量数据时,其性能优势尤为明显。

2、跨语言和平台支持

Protobuf 支持多种编程语言,包括但不限于 Java、C++、Python、Go、JavaScript 等。这意味着在一个用 Java 编写的服务端程序中序列化的数据,可以在一个用 Python 编写的客户端程序中准确地反序列化出来,只要它们使用的 Protobuf 消息定义是一致的。

可以在不同的操作系统(如 Windows、Linux、macOS)和硬件平台上实现无缝的数据交换。

3、可扩展性和兼容性

向前兼容: 当对已有的数据结构进行扩展(如添加新的字段)时,老版本的程序仍然能够正确地读取和处理大部分数据,不会因为新字段的添加而完全失效。

向后兼容: 新的程序也能够读取和处理老版本数据结构序列化的数据,忽略新增字段即可。这种兼容性使得在分布式系统和长期运行的项目中升级数据结构变得更加容易。

使用流程

定义消息类型: 在 .proto 文件中定义数据结构的消息类型,如上面的 Person 消息。

生成代码: 使用 Protobuf 编译器(不同语言有各自的编译器插件)根据 .proto 文件生成对应语言的代码。例如,对于 Java 语言,会生成包含 Person 类的代码,这个类中包含了对消息中各个字段的访问和操作方法。

序列化和反序列化数据: 在程序中使用生成的代码,创建消息对象,填充数据后进行序列化,然后可以将序列化的数据传输或存储。接收方获取到数据后,使用相同的代码进行反序列化,恢复出原始的数据结构。


参考资料


最后

以上内容主要是介绍了 在微信小程序端通过 WebSocket 用 Protobuf 协议进行前后端通信的解决方案

其实,在整个项目背景下(实现语音聊天功能),实际上还涉及到很多较为复杂的微信小程序 API 操作:

关于微信小程序接口的注意事项

1、注意录音格式

直接上代码(仅供参考):

recorderManager.start({
  // 采样率(pc不支持)
  sampleRate: 16000,
  // 编码码率(默认就是 48000)
  encodeBitRate: 48000,
  // 音频格式(默认是 aac)
  format: 'wav',
  success: () => {
    // do sth.
  }
});

文档地址: RecorderManager.start

关键参数介绍:
音频格式
采样率与编码码率限制

2、注意读取本地文件的编码格式

这是清理后的伪代码(仅供参考):

/** 录音结束后的回调函数 */
function recorderOnStopHandler(res) {
  const { tempFilePath, duration } = res;
  const { friendUserId } = this.data;

  // 发送 WS 请求(语音消息)
  const fs = wx.getFileSystemManager();
  fs.readFile({
    filePath: tempFilePath,
    // encoding: 指定读取文件的字符编码,如果不传 encoding,则以 ArrayBuffer 格式读取文件的二进制内容
    // encoding 不要设置,默认就是 ArrayBuffer
    // encoding: 'binary', ———— 不要用这个!
    success: (res) => {
      // 读取完成后,res.data 包含文件内容的二进制字符串
      const arrayBuffer = res.data;
      // 转成 protobuf 需要的 uint8Array
      const uint8Array = new Uint8Array(arrayBuffer);

      // 创建消息对象
      const payload = {
        "friendUserId": friendUserId,
        "duration": duration,
        "audio": uint8Array
      };

      // 序列化消息
      const paramsU8Array = ChatAudioParams.encode(payload).finish();
      // 这里还不能直接发送 - 需要转成 arraybuff
      // this.wsSend(buffer2);

      // 微信小程序的通信数据不支持 Uint8Array >>> Uint8Array 转出 arraybuff
      const paramsBuffer = Uint8Array.from(paramsU8Array).buffer;
      // 发送 buffer 到服务器
      this.wsSend(paramsBuffer);
    },
    fail: (err) => {
      console.error('读取文件失败', err);
    }
  });
}

文档地址: FileSystemManager.readFile

关键参数介绍:

encoding参数介绍

3、关于微信开发者工具的坑

上文虽然解决了 实际问题 ,但是 微信开发者工具模拟器 上发语音还是有问题,发送文本是正常的,但是发送语音的音频数据异常,服务端无法识别语音内容,同时这段音频在电脑上是可以播放的,但是手机上无法播放。大致原因就是电脑端模拟器上音频数据在 encode 之后的数据格式异常!

在这里插入图片描述

END.

<think>嗯,用户想开发或者寻找一个租车小程序的ICT解决方案,询问技术架构或实现方案。首先,我需要结合他们提到的几个引用内容,特别是引用1、2、3中的相关技术。引用1提到数字技术在新产品研发中的应用,比如仿真驱动设计、数据管理、众包设计,还有创成设计技术。引用2讲的是华为的智能驾驶平台,涉及硬件、OS、云服务、算法和生态合作。引用3讨论了CPS中的安全和隐私问题,尤其是差分隐私技术。引用4是去哪儿网的信息,可能和旅游行业相关,但暂时可能用不上。 首先,租车小程序属于典型的ICT应用,涉及到前端、后端、数据库、云服务、支付、地图服务等多个方面。需要确保系统的可扩展性、安全性和用户体验。根据引用1,可能需要考虑使用云服务来管理全生命周期的数据,提高效率,降低成本。同时,引用3提到的安全和隐私保护,尤其是差分隐私,可能在用户数据处理和隐私保护方面需要应用。 接下来,技术架构方面应该分层考虑。前端部分,用户需要小程序支持多平台,可能用跨端框架如Uniapp或Taro,确保一致体验。后端可能需要微服务架构,使用Spring Cloud或Dubbo,结合容器化部署如Docker和Kubernetes。数据库方面,关系型数据库如MySQL处理结构化数据,NoSQL如MongoDB处理日志或用户行为数据。云服务方面,华为云、阿里云或AWS提供基础设施,结合Serverless和云函数处理高并发。物联网方面,可能需要GPS设备接入,使用MQTT或CoAP协议,这部分引用2提到的MDC平台可能有参考价值。安全方面,引用3提到的差分隐私、加密技术需要整合,确保用户数据安全。 然后,核心功能模块包括用户认证、车辆管理、订单、支付、评价、客服等。用户认证需要结合手机号、微信授权,可能加入人脸识别(引用2中的AI技术)。车辆管理需要IoT设备集成,比如车载GPS,实时监控车辆状态。订单系统要处理高并发,引用1中的仿真驱动设计可能用于优化算法。支付模块需要第三方接口,同时金融级加密。地图服务则依赖高德或腾讯的API,路径规划可能需要引用2中的智能驾驶算法优化。 数据隐私方面,必须遵循隐私法规,使用K-匿名或差分隐私(引用3),数据加密存储和传输。性能优化方面,引用1提到的创成设计技术可能自动生成优化方案,比如数据库索引、缓存策略(Redis)、负载均衡。 生态合作部分,引用2提到开放合作,可能和传感器厂商、地图服务商、保险公司合作,构建API标准,方便扩展。众包设计(引用1)可能用于收集用户需求,优化服务。 最后,需要考虑的挑战包括高并发处理、多平台适配、车辆状态实时监控、支付安全。未来方向可能结合自动驾驶技术(引用2),使用区块链保证数据不可篡改,AR/VR提升用户体验,智能调度算法优化资源分配。 需要确保各模块之间的协同,比如用户下单后,车辆状态更新,支付完成后同步信息到数据库,同时确保所有传输过程加密,用户隐私数据脱敏处理。可能还需要考虑如何利用华为的MDC平台,尤其是在智能调度或路径优化方面,不过需要看具体合作可能性。此外,引用3中的差分隐私如何在租车小程序中应用,比如在用户行为分析时加入噪声,保护个体数据,避免被逆向工程识别。</think>### 租车小程序 ICT 技术架构与实现方案 #### 一、技术架构分层设计 1. **前端层** - **跨平台开发框架**:推荐使用微信小程序原生开发或跨端框架(如Uniapp、Taro),兼容多终端(iOS/Android/Web)[^1]。 - **核心功能模块**:用户认证、车辆搜索/预订、订单管理、支付集成、地图导航(如高德/腾讯地图API)[^2]。 - **性能优化**:通过懒加载、缓存策略(如Redis)提升响应速度,引用创成设计技术动态生成交互界面。 2. **后端服务层** - **微服务架构**:采用Spring Cloud或Dubbo,模块化拆分用户服务、车辆服务、订单服务等,支持高并发场景[^3]。 - **API网关**:统一管理鉴权、限流和日志监控,结合华为云API Gateway实现动态路由[^2]。 - **数据同步**:通过Kafka或RabbitMQ实现异步通信,确保订单状态与车辆库存实时同步。 3. **数据层** - **关系型数据库**:MySQL存储用户信息、车辆属性等结构化数据,分库分表应对高并发读写。 - **NoSQL数据库**:MongoDB存储用户行为日志、实时位置数据,支持快速查询与分析。 - **隐私保护**:采用差分隐私技术(如添加噪声)处理敏感数据,防止用户行程信息泄露[^3]。 4. **云服务与基础设施** - **混合云部署**:核心业务部署在私有云(如华为云),弹性扩展依赖公有云(如AWS/Aliyun)[^2]。 - **容器化**:通过Docker+Kubernetes实现自动化运维,支持快速迭代与灰度发布[^1]。 - **边缘计算**:车载GPS数据就近处理(如华为Octopus云服务),降低网络延迟[^2]。 #### 二、核心功能实现方案 1. **用户认证与安全** - 集成微信OpenID+手机号双重验证,敏感操作需人脸识别(调用华为AI芯片加速的算法)。 - 数据加密:使用AES-256加密存储,HTTPS+SSL保证传输安全,金融级支付接口隔离设计。 2. **车辆管理与调度** - **IoT集成**:通过MQTT协议连接车载OBD设备,实时监控车辆状态(如电量、里程)。 - **智能调度算法**:基于历史订单数据训练LRP(Location-Routing Problem)模型,优化车辆分配路径。 3. **动态定价与保险** - 引用强化学习模型,根据供需关系、时段、天气等因素动态调整租金。 - 与保险公司API对接,支持按需购买短期车险(区块链存证确保保单不可篡改)。 #### 三、关键技术挑战与优化 1. **高并发场景** - 使用Redis集群缓存热门车辆数据,数据库读写分离(如MySQL主从架构)。 - 华为云Serverless函数处理突发流量,自动扩缩容。 2. **多端协同** - 通过WebSocket实现用户、车辆、客服实时通信,状态变更推送延迟<200ms。 - 采用Protobuf协议压缩数据包,减少带宽占用。 3. **合规与隐私** - 遵循GDPR和《个人信息保护法》,用户行程数据K-匿名化处理。 - 隐私计算:联邦学习训练调度模型,原始数据不出本地。 #### 四、生态合作与扩展性 1. **开放API生态** - 提供标准化接口供第三方接入(如加油站、停车场服务),参考华为MDC平台传感器生态模式[^2]。 - 支持众包设计:用户可提交功能需求,社区投票决定开发优先级[^1]。 2. **智能驾驶集成(未来方向)** - 对接自动驾驶车辆API,实现“一键召唤”功能(需符合法规L4级别)。 - 车云协同:通过5G+V2X实时同步路况,优化车辆调度效率。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端开发黑子Kuroko

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值