我的 vue+webscoket+protobuf 從零到寫出一個demo的踩坑記錄

簡單解釋下protobuf ,它就是個又小又快的數據傳輸格式。

從網上下載了一個原生js+webscoket+protobuf的demo

找的這個demo是能夠完美運行(注意要在服務器上打開,本地雙擊是沒用的,demo只上傳了前端部分

遇到坑了javascript


當你準備將這個原生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踩坑記前端

相關文章
相關標籤/搜索