前端使用protobuf进行传参
一.proto的理解
1.以.proto结尾的文件是protobuf文件,且.proto是一种传参规则的定义。
2.常用的请求传参方式是json或xml,因为在大多数的语言中这两种轻量型语言都能被其他语言识别到(java、python、javascript、c++等等)。
proto作为区别于前两者且类似于前两者的语言:
* 它是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
* Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
* 你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
二.深入proto的理解
1.重在理解、重在理解、重在理解----------------平常前后端交互过程中最多的传参方式是json,前端将数据转化为json传给后端,后端再将json转化为后台语言能识别到的数据类型
这里拿json进行举例,针对前端的理解:
ler data ={ userName:'admin', pwdWord:'123456' } let jsonData = JSON.stringfy(data) // 然后使用ajax发送请求 // 不要杠我哈,很多同学说我使用axios或者JQ没有转啊,其实这两个库已经帮你完成了这一步
2.重在理解、重在理解----------------在上述代码中,使用了JSON对象提供的api ---- stringfy将数据data对象序列化为json数据类型,同样的。要使用protobuf我们也需要一种api或某种方式将javascript的数据类型转为proto buffer类型,其作用跟json.stringfy()不能说是相同的,简直就是一摸一样。
三.如何在项目中使用protobuf
1.vue项目用的比较多,这里就拿vue项目举例,其他项目一样,引入、然后使用。
2.使用protobuf有两种形式,一种是使用本地的proto文件,第二种是使用字符串类型的protobuf
2.1.使用本地proto文件的message加码或解码
创建本地proto文件。(name.proto)
syntax = "proto3"; //定义proto版本 package allProto; //定义proto文件的包名,这个名字可以随便取,后面需要用到 message HttpUserInfo{ // 定义一个message类,其中message是定义变量的字段,如同var,let,int,char等等 string userName = 1; //在一个message类当中一般情况下 后面的数字具有唯一性 也就是两个字段后面的值不能是一样的 ------一般情况 string userGuid = 2; int32 type = 3; }
现在有一个JS基本类型的数据data
// 类型要与使用的message中的字段类型一样,不要上面使用int32 你给整一个'abcd'
let data={
userName = 'admin',
userGuid = 'LongErGeGe'
type = 1
}
现在要将两者给混合一下,实现json.stringfy的功能
在项目中我们要下载protobufjs,才能使用protobuf的方法
npm install protobufjs -s
既然要使用proto文件中的数据,所以我们必须要使用某些包让vue能访问到proto文件
直接以下代码会报webpack错误
import protoFile from "@/proto/register.proto"
与sass类似,还需要在项目中装protobuf-loader和file-loader包
npm install protobufjs-loader -s
在vue.config.js中我们需要写入一下代码
module.exports = { // 执行 npm run build 统一配置文件路径(本地访问dist/index.html需'./') lintOnSave: false, publicPath: process.env.NODE_ENV === 'production' ? '' : '/', chainWebpack: (config) => { config.module.rule('protobuf').test(/\.proto$/).use('file-loader').loader('file-loader').options({ name: '[name].[ext]', outputPath: 'proto/', }).end() }, }
现在我们在项目中可以使用proto文件对应的对象了
import protoFile from "@/proto/register.proto"
一下就是类似JSON.stringfy的功能了
import protoFile from "@/proto/register.proto"
protobuf.load(protoFile, (err, root) => { if (err) { return } // 定义使用的messageName
// messageName = “包名.messageName“ const UserInfoRequest = root.lookupType(msesageName) // Verify the payload if necessary (i.e. when possibly incomplete or invalid) const errMsg = UserInfoRequest.verify(data) if (errMsg) { console.error('errMsg', errMsg) return } // 创建一个message,data需要被序列化的代码
//data = {
// userName:'admin'
// userGuid:'LongErGeGe'
// type:1
// } let message = UserInfoRequest.create(data) // or use .fromObject if conversion is necessary // 根据创建的message进行系列化Uint8Array let messageBuffer = UserInfoRequest.encode(message).finish() //将Uint8Array 转换为 ArrayBuffer let protoBuffer = messageBuffer.buffer.slice(messageBuffer.byteOffset, messageBuffer.byteOffset + messageBuffer.byteLength) console.log('protoBuffer',protoBuffer) })
以上就是将data根据指定的message序列化的全部过程
2.2 解码
通常指定了使用protobuf传参的规则,那么后端返回的是ArrayBuffer,在使用axios请求时,需要设置responseType:ArrayBuffer
这里假定 response 为请求到的ArrayBuffer数据,使用protobuf.load进行解码
import protoFile from "@/proto/register.proto"
protobuf.load(protoFile, async (err, root) => {
//定义使用的message proto文件的包名.messageName
const UserInfoResponse = root.lookupType(messageName)
var message = await UserInfoResponse.decode(new Uint8Array(response)) //将ArrayBuffer转化为Unit8Array后使用decode方法转化为JS数据类型
console.log('message', message)
})
五.如果proto是远程文件或字符串
1.使用protobuf.parse
//keepCase是否保持大小写
const root = protobuf.parse(protoString, { keepCase: true }).root
然后跟上面一样使用decode或者encode进行加解密