cheungseol / cheungseol.github.io

2 stars 0 forks source link

Protobuf.js 解析 int64 #21

Open cheungseol opened 5 years ago

cheungseol commented 5 years ago

生产环境和开发环境解析PB long64返回格式不一致的问题:生产环境换回了number 类型,开发环境返回 long 类型

背景

protobuf.js 是支持浏览器环境的,但是如果想要支持int64的话,需要额外引入long.js 模块。并且需要项目里提供 global全局的require方法引入 long.js 模块,这样 protobuf.js 才能调用到long.js 模块。

为什么开发环境ok,生产环境不行?

应该是 webpack 打包出来的东西, require 被干掉了,building 之后 没有 global 全局的 require 函数

参考 过时了,已经没有 bytebuffer模块了

解决方案

既然全局的 require 找不到long.js模块,那么就手动在 protobuf.js 中引入 long.js 模块

var Long = ...;

protobuf.util.Long = Long;
protobuf.configure();

为什么加上这么两行代码就可以了?

protobuf.js 是如何解析消息中的 int64 数字的?

以 pb-read.png 为例,当处理到 int64 数字时,

- 如果存在 util.Long,就用 util.Long 的formValue 处理,将int64 转换为 long 型
- 当要处理的目标数字是 string 或者 number 类型时,分别转换成对应类型
- 当要处理的目标数字是 object 类型时,使用 util.LongBits 方法把目标转换为 number 类型。 util.LongBits 是 protobuf.js 自己实现的方法

所以 protobuf.js 在处理int64是需要用到 util.Long 的,那么 util.Long 从何而来?其实也就是 protobuf.js 是怎么引入项目中的 long.js 模块的

protobuf.js 是如何在项目中寻找 long.js 包的?

参考 pb-inqure.png protobuf.js 会首先找全局的 Long 是否窜在,不存在的话 就 inqure 项目中可能存在的 long 模块。而上面的解决方案中是 手动给 util.Long 赋值,传入了 long 模块,同样满足需求

protobuf.js 引入了 long 模块之后,又是怎么使用的?

参考 pb-configure.png 当 util.Long 引入了 long 模块之后,readLongVarint 方法就会使用 toLong 的方式把 int64 转换为 long 型,如果没有引入了 long 模块,那么就使用 toNumber 把 int64 转换为 number 类型

这里的 toLong 和 toNumber 是 protobuf.js 自己实现的 LongBits 类型的方法

参考