前端小工具:protobufjs数据传输

前端使用protobufjs,数据传输protobufjs使用记录

protobuf.js

协议缓冲区是一种与语言无关的、与平台无关的、可扩展的序列化结构化数据的方法,用于通信协议、数据存储等,最初由Google设计(请参阅)。

 

协议.js是一个纯JavaScript实现,支持节点.js和浏览器。它易于使用,速度极快,并且可以与.proto文件一起开箱即用

1, 安装protobufjs

npm install protobufjs [--save --save-prefix=~]

2.使用

// const protobufjs = require('protobufjs')
import protobufjs from 'protobufjs'


// 要用到load模块
  const { load } = protobufjs

实例:

export default class protobuf {
    static exportBuffer(parsedJsonList, molecule, proto , taskitem){
        return new Promise((resolve, reject) => {
            load(proto, (err, root) => {
              if (err) {
                console.log(err)
                return reject(new Error('proto文件加载出错!'));
              }
              let prototxts = []
              parsedJsonList.forEach(parsedJson => {
                let parsedMessage = root.lookupType('TIV.' + parsedJson.header.type + 'Def')
                const single = parsedMessage.create(parsedJson)
                const singleBuffer = parsedMessage.encode(single).finish() // 这个singleBuffer发给后台就好
                prototxts.push({
                  msgId: parsedJson.id,
                  msgType: parsedJson.header.type,
                  msgContent: singleBuffer,
                  taskType: parsedJson.taskType,
                  isEntry: isEntry(parsedJson.header.type, parsedJson.id, molecule)
                })
              })
      
              let prototxtsMessage = root.lookupType('TIV.AllOperatorPb')
              const all = prototxtsMessage.create({
                allOperatorPb: prototxts,
                taskFlow: taskitem ? taskitem : ''
              })
              const allBuffer = prototxtsMessage.encode(all).finish() // 这个buffer发给后台就好
              const b64 = btoa(String.fromCharCode.apply(null, allBuffer))
            //   this.analysisBuffer(b64, proto)
              resolve(b64);
            })
        })
    }
    static analysisBuffer(b64, proto) {
        let allBuffer = atob(b64).split('').map(function (c) { return c.charCodeAt(0) })
        return new Promise((resolve, reject) => {
            load(proto, (err, root) => {
                if (err) {
                    reject(err)
                    return console.log('proto文件加载出错');
                }
                let prototxtsMessage = root.lookupType('TIV.AllOperatorPb')
                const alldata = prototxtsMessage.decode(allBuffer)
                alldata.allOperatorPb.map(item => {
                    let parsMessage = root.lookupType('TIV.' + item.msgType + 'Def')
                    const fields = [];
                    if (Object.keys(parsMessage.Parameter.fields).length > 0) {
                        Object.keys(parsMessage.Parameter.fields).forEach(ikey => {
                            let value = 0;
                            if (parsMessage.Parameter.fields[ikey].type === "bool") {
                                value = false;
                            }
                            fields.push({
                                title: ikey,
                                value: parsMessage.Parameter.fields[ikey].typeDefault || value
                            })
                        })
                    }
                    const prototxt = parsMessage.decode(item.msgContent)
                    fields.forEach(field => {
                        if(prototxt['param']){
                            prototxt['param'][field.title] = prototxt['param'][field.title] ? prototxt['param'][field.title] : field.value;
                        }  
                    })
                    prototxt.header.type = prototxt.header.type.split('Operator')[0]
                    item.msgContent = formatInit(prototxt)
                })
                if(process.env.NODE_ENV === 'development'){
                    console.log('解析后json数据:',alldata.allOperatorPb)
                }
                resolve(alldata.allOperatorPb);
            })
        })
    }
}
protobufjs使用,数据的转换依赖 proto配置文件,protobufjs默认支持本地同源文件请求,如果proto文件是固定的不需要更改的,配置在前端静态文件就好了;如何会动态变更的话,需要用到绝对路径,需要解决跨域问题;

修改protobufjs对象原型默认的load请求文件方式:

protobufjs.util.fetch.xhr = function fetch_xhr(filename, options, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange /* works everywhere */ = function fetchOnReadyStateChange() {

        if (xhr.readyState !== 4)
            return undefined;

        // local cors security errors return status 0 / empty string, too. afaik this cannot be
        // reliably distinguished from an actually empty file for security reasons. feel free
        // to send a pull request if you are aware of a solution.
        if (xhr.status !== 0 && xhr.status !== 200)
            return callback(Error("status " + xhr.status));

        // if binary data is expected, make sure that some sort of array is returned, even if
        // ArrayBuffers are not supported. the binary string fallback, however, is unsafe.
        if (options.binary) {
            var buffer = xhr.response;
            if (!buffer) {
                buffer = [];
                for (var i = 0; i < xhr.responseText.length; ++i)
                    buffer.push(xhr.responseText.charCodeAt(i) & 255);
            }
            return callback(null, typeof Uint8Array !== "undefined" ? new Uint8Array(buffer) : buffer);
        }
        return callback(null, xhr.responseText);
    };

    if (options.binary) {
        // ref: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Receiving_binary_data_in_older_browsers
        if ("overrideMimeType" in xhr)
            xhr.overrideMimeType("text/plain; charset=x-user-defined");
        xhr.responseType = "arraybuffer";
    }

    xhr.open("GET", filename);
    let headers = options.headers || {};

    if (process.env.NODE_ENV !== 'development') {
        headers['X-TC-Action'] = 'WorkbenchPb'
        headers['X-TC-Region'] = 'ap-guangzhou'
        headers['X-TC-Timestamp'] = Math.round(new Date().getTime()/1000).toString()
        headers['X-TC-Service'] = 'AMTPGate'
        headers['X-TC-Version'] = '2020-05-14'
    }

    for (let item in headers) {
        if (headers.hasOwnProperty(item) && headers[item] !== null) {
            xhr.setRequestHeader(item, headers[item]);
        }
    }
    xhr.send();
};
Buffer数据流,传输速度非常快,数据保密性更强,前后端数据传输跟健壮。
文中的示例,最终使用的是base64,这样对ajax请求无影响,直接使用post请求,即可。如果直接用buffer,需要自己封装ajax;
大概设置:
xhr.responseType = 'blob'

 

protobuf.js库很强大,可以继续研究一下。

同时使用protobuf.js,和后端使用规范版本要一致。

 

没有终点,没有彼岸,坚持就好,愿岁月如初

posted @ 2021-01-29 10:40  smallbore  阅读(3587)  评论(0编辑  收藏  举报
回顶部