详解vue中使用protobuf踩坑记


Posted in Javascript onMay 07, 2019

官方解释为:

Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data ? think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.

翻译是(机翻---我英语不好)

协议缓冲区是用于序列化结构化数据的灵活,高效的自动化机制 - 思考XML,但更小,更快,更简单。您可以定义一次数据的结构,然后您可以使用特殊的源代码轻松地将结构化数据写入各种数据流并使用各种语言读取和读取数据。您甚至可以更新您的数据结构,而不会中断根据“旧”格式编译的已部署程序。

特点:

  • 更简单
  • 是3到10倍小
  • 速度要快20到100倍
  • 不太模糊
  • 生成更易于以编程方式使用的数据访问类

代码

在github上写了个demo demo地址 有需要的可以下载下来跑一下就理解了。PS:如果觉得有用 请给我个小星星 (笔芯~)

使用

其实最开始我尝试使用一个第三方JSprotobuf.js protobuf.load 的时候浏览器报了个错illegal token '<' (/demo.proto, line 1) 查找了下官网issue,大意应该是proto文件多了个字符,但是我查看过proto文件并没有发现有多的'<',怎么办呢,最后放弃使用第三方。用官方提供的方法。

下载protobuf编译器

下载地址 (我下载的是3.40版) github也提供了zip包,可自行下载 (目前最新版本是v3.6.0) 用来编译proto为JS文件方便调用

配置环境变量

由于公司用的是win10 只需要将下载的文件地址添加到path即可 Mac与window命令唯一的区别就是需要将protoc改成protoc.exe 前提是需要添加环境变量

编写proto文件

为了确保前后一致,下面是后台写给我的一个测试proto,我司后台是java

syntax = "proto2";//protobuf版本
option java_package = "com.test.protobuf";
option java_outer_classname = "PersonMessage";
message Person {
 required int32 id = 1;
 optional string name = 2;
 optional string email = 3;
 repeated string list = 4;
 extensions 100 to 1000;//允许扩展的ID
}

message PersonTree {
 optional string id = 1;
 optional string title = 2;
 repeated PersonTree childs = 3;
}

extend Person {
 optional int32 count = 101;
 optional int32 likes_cnt= 102;
}

message PersonEx {
 optional int32 id = 1;
 extend Person {
  optional int32 px = 103;
  optional int32 py= 104;
 }
 optional Person p = 2;
}

使用vue-cli构建一个工程目录

npm install -g vue-cli
vue init webpack my-project
cd my-project
npm install
npm run dev

安装插件: npm install axios element-ui google-protobuf --save

编译proto为JS

进入 awesome.proto 的存放路径 使用如下命令 protoc.exe --js_out=import_style=commonjs,binary:. awesome.proto

  • 会生成一个awesome_pb.js文件
  • 点击查看awesome_pb.js其实可以看到里面是生成好的方法。只需要在页面中引入JS调用即可

之后我们将这个文件引入页面,当然你也可以考虑全局引用

测试

本地测试

编写一个测试页面,创建一个测试按钮 我是在测试页面 import messages from './awesome_pb.js' 方法为:

methods: {
  protobufferTest () {
   var message = new messages.Person() // 调用Person对象 实例化
   // 赋值
   message.setId(23)
   message.setName('asd')
   // 序列化
   var bytes = message.serializeBinary()

   console.log(bytes) // Uint8Array(7) [8, 23, 18, 3, 97, 115, 100]

   // 反序列化
   var message2 = messages.Person.deserializeBinary(bytes)

   console.log(message2) // proto.PersonTree {wrappers_: null, messageId_: undefined, arrayIndexOffset_: -1, array: Array(3), pivot_: 1.7976931348623157e+308, …}

  }
 }

到此,本地测试完成,没什么毛病了。

前后端联调测试

前方有坑

前后传输是使用的FormData,然后悲剧的事情来了。后台解析不了。查看了下数据 [8, 23, 18, 3, 97, 115, 100] 确实是传过去了。

后来排查出原因是应该是解析成了字符串,然后数值变了。所以解析不出来。 后来使用fromCharCode()方法编辑成字符串形式传输给后台。在使用charCodeAt()取值。

此方法已弃用
protobufferTest () {
   var message = new messages.Person() // 调用Person对象 实例化
   // 赋值
   message.setId(23)
   message.setName('asd')
   // 序列化
   var bytes = message.serializeBinary()

   console.log(bytes) // Uint8Array(7) [8, 23, 18, 3, 97, 115, 100]

   var tests = ''
   for (let index = 0; index < bytes.length; index++) {
    tests += String.fromCharCode(bytes[index])
   }
   console.log(tests) // asd

   // 存入FormData
   let uploadDatas = new FormData()
   uploadDatas.append('protobuf', tests)

   // 使用axios传输给后台
   this.axios.post('/test', uploadDatas)
    .then(function (response) {
     // 将传回的字符串转为数组
     console.log(response.data.split('')) // ["↵", "", "3", "2", "", "", "a", "s", "d", "f"]
     let str = response.data.split('')
     let toChar = []
     for (let index = 0; index < str.length; index++) {
      toChar.push(str[index].charCodeAt())
     }
     console.log(toChar) // [10, 2, 51, 50, 18, 4, 97, 115, 100, 102]

     // 后台传回来的是PersonTree里面的值所以调用PersonTree来反序列化
     var message2 = messages.PersonTree.deserializeBinary(toChar)

     console.log(message2) // proto.PersonTree {wrappers_: null, messageId_: undefined, arrayIndexOffset_: -1, array: Array(3), pivot_: 1.7976931348623157e+308, …}

     // 获取PersonTree的id值
     console.log(message2.getId()) // 32
    })
    .catch(function (error) {
     console.log(error)
    })

  }

以上方法可能存在安全隐患。 向后端传值 因为FormData支持两种方式传输string和blob所以将bytes存入blob中 前端获取数据 对axios的默认传输方式做个更改 axios.defaults.responseType = 'arraybuffer' 将以上的JS代码更改为以下内容

protobufferTest () {
   var message = new messages.Person()
   message.setId(23)
   message.setName('asd')
   var bytes = message.serializeBinary()
   
   console.log(bytes)
   let uploadDatas = new FormData()
   var blob = new Blob([bytes], {type: 'application/octet-stream'})

   uploadDatas.append('protobuf', blob)
   
   this.axios.post('/test', uploadDatas)
    .then(function (response) {
     console.log(response)

     var message2 = messages.PersonTree.deserializeBinary(response.data)
     console.log(message2.getId())
    })
    .catch(function (error) {
     console.log(error)
    })
   // console.log(bytes)
  }

至此前后联调完成

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ASP.NET中使用后端代码注册脚本 生成JQUERY-EASYUI的界面错位的解决方法
Jun 12 Javascript
firefox火狐浏览器与与ie兼容的2个问题总结
Jul 20 Javascript
javascript完美拖拽的实现方法
Sep 29 Javascript
超精准的javascript验证身份证号的具体实现方法
Nov 18 Javascript
Javascript动画效果(1)
Oct 11 Javascript
JS中split()用法(将字符串按指定符号分割成数组)
Oct 24 Javascript
JS实现根据用户输入分钟进行倒计时功能
Nov 14 Javascript
详解webpack的配置文件entry与output
Aug 21 Javascript
详解javascript中的babel到底是什么
Jun 21 Javascript
详解vue-cli3 中跨域解决方案
Apr 10 Javascript
原生JS封装拖动验证滑块的实现代码示例
Jun 01 Javascript
如何使用JS console.log()技巧提高工作效率
Oct 14 Javascript
Node.js一行代码实现静态文件服务器的方法步骤
May 07 #Javascript
微信小程序扫描二维码获取信息实例详解
May 07 #Javascript
Vue数据绑定简析小结
May 07 #Javascript
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
May 07 #Javascript
详解Vue、element-ui、axios实现省市区三级联动
May 07 #Javascript
webpack结合express实现自动刷新的方法
May 07 #Javascript
记录一次开发微信网页分享的步骤
May 07 #Javascript
You might like
自己动手做一个SQL解释器
2006/10/09 PHP
一个从别的网站抓取信息的例子(域名查询)
2006/10/09 PHP
详解WordPress中分类函数wp_list_categories的使用
2016/01/04 PHP
PHP常用函数总结(180多个)
2016/12/25 PHP
PHP在linux上执行外部命令的方法
2017/02/06 PHP
Laravel学习教程之本地化模块
2017/08/18 PHP
PHP实现求解最长公共子串问题的方法
2017/11/17 PHP
基于laravel-admin 后台 列表标签背景的使用方法
2019/10/03 PHP
JQUERY复选框CHECKBOX全选,取消全选
2008/08/30 Javascript
IE6 hack for js 集锦
2014/09/23 Javascript
jQuery中:not选择器用法实例
2014/12/30 Javascript
js调用webservice构造SOAP进行身份验证
2016/04/27 Javascript
javascript实现获取图片大小及图片等比缩放的方法
2016/11/24 Javascript
详解NodeJs支付宝移动支付签名及验签
2017/01/06 NodeJs
React复制到剪贴板的示例代码
2017/08/22 Javascript
如何使用vuex实现兄弟组件通信
2018/11/02 Javascript
微信小程序实现侧边分类栏
2019/10/21 Javascript
vue项目中定义全局变量、函数的几种方法
2019/11/08 Javascript
js实现鼠标点击页面弹出自定义文字效果
2019/12/24 Javascript
Element DateTimePicker日期时间选择器的使用示例
2020/07/27 Javascript
[53:49]LGD vs Fnatic 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python 判断一个进程是否存在
2009/04/09 Python
从零学Python之入门(四)运算
2014/05/27 Python
Python的高级Git库 Gittle
2014/09/22 Python
Python中扩展包的安装方法详解
2017/06/14 Python
python监控进程脚本
2018/04/12 Python
Python面向对象程序设计之静态方法、类方法、属性方法原理与用法分析
2020/03/23 Python
opencv-python的RGB与BGR互转方式
2020/06/02 Python
html5+css3气泡组件的实现
2014/11/21 HTML / CSS
Asics日本官网:鬼冢八喜郎创立的跑鞋运动品牌
2017/10/18 全球购物
C#笔试题集合
2013/06/21 面试题
C# .NET面试题
2015/11/28 面试题
如何将无状态会话Bean发布为WEB服务,只有无状态会话Bean可以发布为WEB服务?
2015/12/03 面试题
如何整合JQuery和Prototype
2014/01/31 面试题
建筑安全生产责任书
2014/07/22 职场文书
卫生厅领导班子党的群众路线教育实践活动整改措施
2014/09/20 职场文书