Because the company needs to use protobuf, then there is this dent record

What is a protobuf?

The official explanation:

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.

My English is not good.

Protocol buffers are a flexible, efficient automation mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You can define the structure of the data once, and then you can easily write structured data to various data streams using special source code and read and read the data in various languages. You can even update your data structures without interrupting deployed programs compiled according to the “old” format.

Features:

  • More simple
  • It’s 3 to 10 times smaller
  • It’s 20 to 100 times faster
  • Not too vague
  • Generate data access classes that are easier to use programmatically

code

I wrote a demo address on Github. If you need it, you can download it and run it to understand. PS: If you feel useful, please give me a little star (pen core ~)

use

Illegal token ‘<‘ (/demo.proto, illegal token ‘<‘ (/demo.proto, Line 1) CHECKED the official website issue, the general idea should be that the proto file has too many characters, but I checked the proTO file and did not find many ‘<‘, what should I do? Finally, I gave up using the third party. Use the official method.

Download the Protobuf compiler

Github also provides a zip package that you can download yourself (the latest version is v3.6.0) to compile proto into JS files

Configuring environment Variables

The only difference between Mac and Window commands is that you need to change protoc to protoc. Exe if you need to add environment variables to configure environment for reference in this article

Write proto files

In order to ensure consistency, the following is a test proTO written to me by the background. The background of our company is Java

syntax = "proto2"; // Protobuf version 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; } 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; }Copy the code

Build a project directory using vue-CLI

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

NPM install axios element- UI Google -protobuf –save

Compile proto to JS

Protoc. Exe –js_out=import_style=commonjs,binary:.awesome. Proto

  • Will generate aawesome_pb.jsfile
  • Click to viewawesome_pb.jsAnd you can actually see that there’s a good way to generate. Just introduce a JS call to the page

Later we’ll import this file to the page, but you can also consider global references

test

Local test

Import messages from ‘./awesome_pb.js’

methods: {
    protobufferTest () {
      var message = new messages.Person() // Call the Person object to instantiate
      / / assignment
      message.setId(23)
      message.setName('asd')
      / / the serialization
      var bytes = message.serializeBinary()

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

      // deserialize
      var message2 = messages.Person.deserializeBinary(bytes)

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

At this point, the local tests are done, and there’s nothing wrong with them.

Front and rear end joint test

In front of a pit

The forward and backward transfer was using FormData, and then the tragic thing happened. The background doesn’t parse. I checked the data [8, 23, 18, 3, 97, 115, 100] and it did pass. It was later checked that the reason should have been parsed into a string, and then the value changed. So it doesn’t work out. The fromCharCode() method is then used to edit it into a string and pass it to the background. The charCodeAt() value is used.

ProtobufferTest () {this method is deprecatedvar message = new messages.Person() // Call the Person object to instantiate
      / / assignment
      message.setId(23)
      message.setName('asd')
      / / the serialization
      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

      / / in the FormData
      let uploadDatas = new FormData()
      uploadDatas.append('protobuf', tests)

      // Use axios to transmit to the background
      this.axios.post('/test', uploadDatas)
        .then(function (response) {
          // Convert the returned string to an array
          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]

          // The background returns the value from PersonTree, so call PersonTree to deserialize it
          var message2 = messages.PersonTree.deserializeBinary(toChar)

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

          // Get the id of the PersonTree
          console.log(message2.getId()) / / 32
        })
        .catch(function (error) {
          console.log(error)
        })

    }
Copy the code

The above methods may have security risks. Back end value Because FormData supports two ways to transfer the string and blob so deposited the bytes in a blob of front end to get the data changes on the default transport axios axios. Defaults. ResponseType = ‘arraybuffer’ Change the JS code above to the following

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)
    }

Copy the code

So far before and after the joint investigation is completed

Reference documentation

Use Google-Protobuf in front end, back end and game

How does the javascript front end use Google-Protobuf