宝哥软件园

在vue中使用protobuf的过程记录

编辑:宝哥软件园 来源:互联网 时间:2021-08-29

目前,ProtoBuf用于公司的前端和后端数据交换。进入公司以来,一直使用公司大神编写的基础数据库。我们不知道底层是如何解决的。一旦我们报告错误,我们只能寻求帮助。作为一个有学习精神的猿猴,我们应该了解底层的实现,并在这里记录学习过程。

原蟾简介

Google Protocol buff(proto buf)是一种可移植、高效的结构化数据存储格式,具有平台无关、语言无关、可扩展等特点,可用于通信协议和数据存储领域。

有几个优点:

1.平台无关、语言无关和可扩展;2.它提供了友好的动态库,易于使用;3.解析速度快,比对应的XML快20-100倍左右;4.序列化数据非常简洁紧凑。与XML相比,序列化数据量约为1/3到1/10。

个人经验:对于前端的数据传输,json和protobuf没有太大区别,protobuf只有解析成json才能使用。个人觉得比较好的点是:

1.protobuf可以直接在项目的前端和后端使用,不需要定义模型;此外;2.protobuf可以直接作为前端数据和接口的文档,大大降低了通信成本;

在使用protobuf之前,后端语言定义的接口和字段不能被前端直接使用。通常需要维护一个用于前端通信的接口文档。如果后端字段发生变化,需要修改文档并通知前端。有时文档更新不及时或容易遗漏,沟通成本相对较高。protobuf使用后,protobuf文件由后端统一定义,protobuf可以直接作为文档使用,前端只需要将protobuf文件复制到前端项目中即可。如果后端字段发生变化,只需通知前端更新protobuf文件即可,因为后端直接使用protobuf文件,所以protobuf文件一般不会丢失或出错。从长远来看,团队合作效率的提升是明显的。

一大堆废话,言归正传。我这里说的主要是在vue中的应用,这是我公司目前的项目实践,大家可以作为参考。

思路

前端需要使用protobuf.js作为库来处理proto文件。

Protobuf.js提供了几种处理proto的方法。

Protobuf.load('太棒了。proto ',函数(err,root){ 0.}) Protobuf.load('真棒。JSON ',函数(err,root){ 0.})众所周知,只有html、css,js、图像等资源中没有. proto文件,所以需要用protobuf.js库来处理*。原型变成*。js或*。json,然后使用库提供的方法解析数据,最后得到数据对象。

根据PS:的实践,转换成js文件比较好,转换后的js文件直接定义了原型链中的一些方法,非常方便。因此,这个方法将在以后用于解析proto。

预期目标

将request.js模块封装在项目中。希望可以如下使用。调用api时,我只需要指定请求和响应的模型,然后传递请求参数。我不在乎底层如何解析proto。应用编程接口返回一个承诺对象:

///api/student.js定义来自‘@/lib/request‘//params的接口文件导入请求是对象类型//school的请求参数。PBStudentListReq是定义的请求体模型//School。PBStudentListRsp是一个已定义的响应模型//getStudentList是接口名导出函数getStudentList(params){ const req=request . create(' school。参数)返回请求(' getStudentList ',请求,学校。pbstudentlistersp ')}//使用import {getstudentlist}从' @/API/student '导出HelloWorld.vue中的默认{name:' helloworld ',Created () {},methods : { _ getstudentlist(){ const req={ limit=20,offset=0} getstudentlist (req)。然后((RES)={console.log (RES)})。catch ((RES)={console。

1.获取已定义的原型文件。

虽然语法简单,但实际上前端并不太关心如何编写proto文件,proto文件一般由后端定义和维护。在这里,您可以直接使用我定义的演示。

//User.protopackage框架;语法=' proto3消息PBUSer { uint 64 USer _ id=0;字符串名称=1;字符串mobile=2;}//Class.protopackage学校;语法=' proto3消息pbCLaSS { uint 64 CLaSS id=0;字符串名称=1;}//Student.protopackage学校;语法=' proto3导入“user . proto”;导入“class . proto”;消息PBStudent { uint 64 studentId=0;pbUSer user=1;pbCLaSS class=2;PBStudentDegree}枚举PBStudentDegree { PRIMAry=0;//小学生的中等=1;//中学生高年级=2;//高中生COLLEGE=3;//大学生} message pbstudentlistreq { uint 32 offset=1;uint32限制=2;}消息PBStudentListRsp {重复的PBStudent列表=1;}//MessageType.protopackage框架;语法=' proto3//公共请求正文messagepbmessagerequest { uint 32 type=1;//消息类型字节messageData=2;//请求数据uint64时间戳=3;//客户端时间戳字符串版本=4;//api版本号字符串标记=14;//用户登录进行登录验证后服务器返回的令牌}//消息响应包messagepbmessageresponse { uint 32 type=3;//消息类型字节messageData=4;//返回数据uint 32 result code=6;//返回的结果代码为字符串resultInfo=7;//返回结果消息提示文本(用于错误提示)}//与学生相关的所有接口的enumbmessagetype {//getstudentlist=0;//获取所有学生的列表,pbstudentlistreq=pbstudentlistersp }其实不用学习proto的语法,一眼就能看出来。有两个名称空间:框架和学校。PBStudent指的是PBUser,因此可以认为PBStudent继承了PBUser。

一般来说,前端和后端需要统一约束一个请求模型和一个响应模型,比如请求中哪些字段是必需的,返回体中哪些字段是必需的。这里,MessageType.proto的PBMessageRequest用于定义请求体所需的字段,PBMessageResponse定义为返回体的字段。

PBMessageType是接口的枚举,后端的所有接口都写在这里,注释用来指示具体的请求参数和返回参数类型。例如,这里只定义了一个接口getStudentList。

拿到*后。后端提供的proto文件,你能基本知道有一个getStudentList的接口,请求参数是PBStudentListReq,返回的参数是PBStudentListRsp吗?

因此,proto文件可以直接用作前端通信的文档。

步骤

1.创建新的vue项目

同时添加和安装axios和protobufjs。

# vue create vue-protobuf # NPM安装axios protobufjs-save-dev2。在src目录下创建一个新的原型目录来存储*。原型文件,并将写好的原型文件复制到其中。

此时的项目目录和包. json:

3.从*生成src/proto/proto.js。原型文件(关键点)

Protobufjs提供了一个叫做pbjs的工具,它是一个工件,可以根据不同的参数打包成xx.json或者xx.js文件。例如,我们希望将其打包为json文件,并在根目录下运行:

Nxpbjs-t JSON src/proto/*。protosrc/proto/proto.json可以在src/proto目录下生成一个proto.json文件,请点击这里查看。就像我之前说的:实践证明,最好打包js模块。我直接在这里下达最后的命令

参数npx bjs-TJ son-module-w common js-o src/proto/proto . js src/proto/*。proto-w可以指定包装js的包装器。这里,我们使用commonjs。详情请阅读文件。运行命令后,在src/proto目录中生成Proto.js。点击chrome中的console.log(proto.js)中的:

可以发现,这个模块在原型链上定义了加载、查找和其他非常有用的API,我们将在后面使用。为了将来方便起见,我们将命令添加到package.json的脚本中:

脚本' : { ' serve ' : ' vue-CLI-service serve ',' build ' : ' vue-CLI-service build ',' lint': 'vue-cli-service lint ',Proto ' : ' pbjs-t JSON-module-w common js-o src/Proto/Proto . jssrc/Proto/*。proto'},以后更新proto文件后,只需要NPM运行proto就可以重新生成最新的proto.js

4.包请求. js

proto.js文件生成后,您可以开始封装与后端交互的基本模块。首先,我们应该知道我们在这里使用axios发起http请求。

整个过程:开始调用接口-request.js把数据变成二进制-前端真正发起请求-后端返回二进制数据-request.js处理二进制数据-获取数据对象。

可以说request.js相当于一个中继站进行加解密。在src/lib目录中添加一个request.js文件,开始开发:

由于我们的接口都是二进制数据,我们需要设置axios的请求头并使用arraybuffer,如下所示:

从' axios ' const HttpServiCe=axios . create({ timeout : 45000,method: 'post ',Headers : { ' x-requested-with ' : ' xmlhttprequest ',' content-type ' : ' application/octet-stream ' },response type : ' arraybuffer ' })messagetype . proto定义接口枚举,请求者和响应者与后端达成一致。在发起请求之前,所有请求都需要转换成二进制。下面是request.js的主要功能

从" @/proto/proto "导入原型根从" protobufjs"//导入原蟾蜍请求体messageconst PBMessageRequest=ProToroot。查找('框架.PBMessageRequest’)//响应体的messageconst PBMessageResponse=ProToroot。查找('框架.PBMessageResponse)常量APiversion=' 1。0 .0 ' const token=' my _ token '函数getMessageTypeValue(msgType){ const PBMessageType=proto root。查找('框架.PBMessageType’)常量ret=PBMessageType。值[MSgtype]返回ret}/** * * @param {*} msgType接口名称* @param {*} requestBody请求体参数* @param {*} responseType返回值*/函数请求(msgType、requestBody、responseType) { //得到美国石油学会(美国石油协会)的枚举值const _ MSgtype=GetmessageTypeValue(MSgtype)//请求需要的数据常量请求数据={时间戳:新日期().getTime(),type: _msgType,version: apiVersion,messageData: requestBody,token: token }} //将对象序列化成请求体实例const req=pbmessagerequest。创建(请求数据)//调用爱可信发起请求//这里用到爱可信的配置项:transformRequest和转换响应//转换请求发起请求时,调用transformRequest方法,目的是将请求转换成二进制//transformResponse对返回的数据进行处理,目的是将二进制转换成真正的数据数据返回httpService.post('/api ',req,{ transformRequest,transformresponse : transformresponse工厂(响应类型)}).然后(({数据,状态})={ //对请求做处理如果(状态!==200) {常量错误=新错误('服务器异常)throw err } console.log(data) },(err)={ throw err })}//将请求数据编码成二进制编码是proto.js提供的方法函数transformRequest(数据){返回PBMessageRequest.encode(数据)。完成()}函数isArrayBuffer(obj){ return对象。原型。tostring。调用(obj)='[对象ArrayBuffer]' }函数transformResponse工厂(响应类型){ return函数transform response(raw response){//判断反应是否是arrayBuffer if(RawResponse==null | |!isArrayBuffer(raw response)){ return raw response }尝试{ const buf=proto buf。乌提尔。新缓冲区(RawResponse)//解码响应体const解码响应=pbmessageresponse。解码(buf)if(解码响应。messagedata响应类型){ const model=proto root。查找(响应类型)解码响应。messagedata=模型。解码(解码的响应。messagedata)}返回解码的响应} catch(err){ return err } }//在请求下添加一个方法,方便用于处理请求参数request.create=function(质子化名称,obj){ const pbConstruct=proto root。查找(质子化名称)返回pbConstruct.encode(obj).finish()}//将模块暴露出去导出默认请求最后写好的具体代码请看:request.js。其中用到了查找(),编码(),完成(),解码()等几个proto.js提供的方法。

5.调用request.js

在。某视频剪辑软件文件直接调用美国石油学会(美国石油协会)前,我们一般不直接使用request.js来直接发起请求,而是将所有的接口再封装一层,因为直接使用request.js时要指定请求体,响应体等固定的值,多次使用会造成代码冗余。

我们习惯上在项目中将所有后端的接口放在src/api的目录下,如针对学生的接口就放在src/api/student.js文件中,方便管理。将getStudentList的接口写在src/api/student.js中

从" @/lib/request"//params导入请求是目标类型的请求参数//学校PBStudentListReq .是定义好的请求体模特//学校pbstudentlistersp .是定义好的响应model//getStudentList是接口名称导出函数getStudentList(params){ const req=request。创建(' PBStudentListReq ',参数)返回请求(' getStudentList ',req,' school .pbstudentlistsp ')}//后面如果再添加接口直接以此类推导出函数getStudentById (id) { //const req=.//返回请求(.)}6.在。某视频剪辑软件中使用接口

需要哪个接口,就进口哪个接口,返回的是承诺对象,非常方便。

模板div class=' hello ' button @ click=' _ getStudentList '从' @/API/student ' export default { name : ' hello world ',methods : { _ getStudentList(){ const req={ limit : 20,Offset : 0 } getStudentList(req)获取学生列表/button/div/templatescript { getStudentList }。然后((RES)={console.log (RES)})。catch((RES)={ console . error(RES)})} },created(){ }/script style lang=' SCS '/style summary

整个演示的代码:演示。

前端使用的整个过程:

1.将后端提供的所有proto文件复制到src/proto文件夹2中。运行npm运行proto根据接口枚举4在src/api下生成proto.js3写接口。在vue文件中使用接口。(1和2可以组合起来编写一个自动化脚本,每次更新只需要运行一次)。

文笔比较啰嗦,文笔不好。你会原谅我的。

这个过程是proto的一个前端实践,我觉得比较好,但可能不是最好的。如果贵公司还有其他更好的做法,欢迎分享。

后续行动

它需要打包到一个js模块中,以便在vue中使用(这是因为vue在生产环境中只打包到html、css、js和其他文件中)。但是,在某些情况下,例如节点环境、快速项目和生产环境。允许出现原型文件。此时可以使用protobuf.js提供的其他方法动态解析proto,不再需要npm运行proto。

以上是边肖介绍的vue使用protobuf的过程记录。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

更多资讯
游戏推荐
更多+