1
简单解释下protobuf ,它就是个又小又快的数据传输格式。

从网上下载了一个原生js+webscoket+protobuf的demo

找的这个demo是可以完美运行(注意要在服务器上打开,本地双击是没用的,demo只上传了前端部分

遇到坑了


当你准备将这个原生js的demo修改成vue项目时,你就会遇到第一个坑了,引入后台给的 xxxx.proto文件的时候会报 illegal token '<' (/xxxx.proto, line 1) ,第一行缺少‘<’这玩意,但源码里没有这个,网上查也有老哥遇到这种情况。所以直接修改时行不通的。

重头来过 从安装protobuf编译器开始吧

vue中使用protobuf踩坑记 这位老哥的文章讲的很详细,我就是参照文章里的步骤走下来的,读者移步去将文章看完再回来看下面的吧

webscoket配置的代码

<template>
  <div class="hello">
    <h1>欢迎访问客服系统</h1>

<form onsubmit="return false">

    <textarea name="message" style="width: 400px;height: 200px" v-model="textarea"></textarea>

    <input type="button" value="发送数据" @click="send();">

    <h3>回复消息:</h3>

    <textarea id="responseText" style="width: 400px;height: 300px;"></textarea>

    <input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空数据">
</form>
  </div>
</template>

<script>
import protoRoot  from '@/proto/proto.js'//我这里生成的文件名为proto
import protobuf from "protobufjs"
export default {
  name: 'HelloWorld',
  data () {
    return {
      socket:null,
      webSocketConfig:{
        url:'192.168.1.9:8899'
      },
      textarea:''
    }
  },
  mounted(){
      this.webscoket()
     
  },
  methods:{
    // 初始化webscoket
    
    webscoket(){
        const _this = this;
        if ('WebSocket' in window) {
          if (_this.socket == null)
            _this.socket = new WebSocket("ws:" + _this.webSocketConfig.url + "/ws");
          else
            _this.socket.onopen();
        } else if ('MozWebSocket' in window) {
          _this.socket = new MozWebSocket("ws:" + _this.webSocketConfig.url + "/ws");
        } else {
          _this.socket = new SockJS(_this.webSocketConfig.projectName + "sockjs/ws");
        }
         //客户端收到服务器消息的时候就会执行这个回调方法
         _this.socket.onmessage = function (event) {
          // 解码
           _this.responseUserDecoder({
             data:event.data,
             success: function (responseData) {
                var ta = document.getElementById("responseText");
                var content = "客服小姐姐: " + responseData.userName +
                        ", 小姐姐年龄: " + responseData.age +
                        ", 密码: " + responseData.password;

                    ta.value = ta.value + "\n" + content;
             }
           })
        }

        //连接建立的回调函数
        _this.socket.onopen = function (event) {
            var ta = document.getElementById("responseText");
            ta.value = "连接开启";
        }
         //连接报错的回调函数
         _this.socket.onerror = function (evnt) {
          console.log("error...");
          console.log(evnt);
        };
        //连接断掉的回调函数
        _this.socket.onclose = function (event) {
            var ta = document.getElementById("responseText");
            ta.value = ta.value + "\n" + "连接关闭";
        }
    },
    //发送数据
    send(){
      let _this=this
      if (!window.WebSocket) {
            return;
        }
        // socket.binaryType = "arraybuffer";

        // 判断是否开启
        if (_this.socket.readyState !== WebSocket.OPEN) {
            alert("连接没有开启");
            return;
        }

        var data = {
            userName: _this.textarea,
            age: 18,
            password: "11111"
        };
        _this.requestUserEncoder({
          data:data,
          success:function(buffer){
            _this.socket.send(buffer);
          }
        });
      
    },
     /**
     * 发送的消息编码成 protobuf
     */
    requestUserEncoder(obj){
        var data = obj.data;
        var success = obj.success; // 成功的回调
        const RequestUser = protoRoot.lookup('com.example.nettydemo.protobuf.RequestUser')
        var buffer=RequestUser.encode(data).finish()
          if (typeof success === "function") {
            success(buffer)
          }

    },
     /**
     * 接收到服务器二进制流的消息进行解码
     */
    responseUserDecoder(obj){
      var data = obj.data;
      var success = obj.success; // 成功的回调
      const ResponseUser = protoRoot.lookup('com.example.nettydemo.protobuf.ResponseUser')
      var reader = new FileReader();
      reader.readAsArrayBuffer(data);
       reader.onload = function (e) {
          var buf = new Uint8Array(reader.result);
          var responseData = ResponseUser.decode(buf);
          if (typeof success === "function") {
              success(responseData)
          }
      }
    }
  }
}
</script>

后台给的文件代码参考

syntax ="proto2";

package com.example.nettydemo.protobuf;

//optimize_for 加快解析的速度
option optimize_for = SPEED;
option java_package = "com.example.nettydemo.protobuf";
option java_outer_classname="MessageData";

// 客户端发送过来的消息实体
message RequestUser{
    optional string user_name = 1;
    optional int32 age = 2;
    optional string password = 3;
}

// 返回给客户端的消息实体
message ResponseUser{
    optional string user_name = 1;
    optional int32 age = 2;
    optional string password = 3;
}

后台给的文件编译生成proto.js代码参考

/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
"use strict";

var $protobuf = require("protobufjs/light");

var $root = ($protobuf.roots["default"] || ($protobuf.roots["default"] = new $protobuf.Root()))
.addJSON({
  com: {
    nested: {
      example: {
        nested: {
          nettydemo: {
            nested: {
              protobuf: {
                options: {
                  optimize_for: "SPEED",
                  java_package: "com.example.nettydemo.protobuf",
                  java_outer_classname: "MessageData"
                },
                nested: {
                  RequestUser: {
                    fields: {
                      userName: {
                        type: "string",
                        id: 1
                      },
                      age: {
                        type: "int32",
                        id: 2
                      },
                      password: {
                        type: "string",
                        id: 3
                      }
                    }
                  },
                  ResponseUser: {
                    fields: {
                      userName: {
                        type: "string",
                        id: 1
                      },
                      age: {
                        type: "int32",
                        id: 2
                      },
                      password: {
                        type: "string",
                        id: 3
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
});

module.exports = $root;

参考文档

xiaosi:vue中使用protobuf踩坑记


JSWalkingMan
3 声望0 粉丝