马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
媒介
故事配景
简单说下配景,项目中必要用 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 这个使用教程的时间,会看到下面这个安装指引。
这里必要重点阐明一下,之前只要实行 npm install protobufjs --save
这端安装脚本之后,就可以使用 pbjs 下令的,但是!改了!统统都变了!请看官方阐明—— pbjs-for-javascript
这里重点吐槽一下,上面截图中的 its own package 点已往还是个404页面!以是,这里我们只能通过 protobufjs 在安装指引中提到的 protobufjs-cli 遐想推测应该指的就是这个库了!
3、具体步调
综上所述,你要做的就是:
步调一:安装 npm 包
- npm install protobufjs --save
复制代码
- 打开你的电脑终端(这里我以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文件 内部的一行代码,具体如下:
步调四:使用天生的 xxx.js 文件
在我们的业务代码中使用通过 pbjs 天生的 JS文件 ,具体细节如下:
1、导入 protobuf 的方法
2、使用 protobuf 实例对象中的属性与方法(encode、decode这些)
3、原来这部门是要放到 灵异事故2 去讲授引出的,为了确保上下文的完备性,这里直接交代结果了。
关键代码:
- 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 去讲授引出的,为了确保上下文的完备性, 这里直接交代结果了。
关键代码:
- 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 类的代码,这个类中包罗了对消息中各个字段的访问和操纵方法。
序列化和反序列化数据: 在步伐中使用天生的代码,创建消息对象,添补数据后举行序列化,然后可以将序列化的数据传输或存储。汲取方获取到数据后,使用类似的代码举行反序列化,规复出原始的数据布局。
参考资料
- protobufjs
- ts-proto
- pbjs-for-javascript
- Language Guide (proto 3)
- 如安在前端中使用protobuf(vue篇)
- 微信小步伐使用protobuf
- 小步伐websocket 通讯 发送 protobuf数据 Uint8Array 非常?
末了
以上内容重要是先容了 在微信小步伐端通过 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);
- const paramsBuffer = Uint8Array.from(paramsU8Array).buffer;
- // 发送 buffer 到服务器
- this.wsSend(paramsBuffer);
- },
- fail: (err) => {
- console.error('读取文件失败', err);
- }
- });
- }
复制代码 文档地点: FileSystemManager.readFile
关键参数先容:
3、关于微信开发者工具的坑
上文固然办理了 现实标题 ,但是 微信开发者工具 的 模仿器 上发语音还是有标题,发送文本是正常的,但是发送语音的音频数据非常,服务端无法辨认语音内容,同时这段音频在电脑上是可以播放的,但是手机上无法播放。大抵缘故原由就是电脑端模仿器上音频数据在 encode 之后的数据格式非常!
END.
|