扫一扫分享
protobuf.js是一个纯JavaScript实现,支持Node.js和浏览器的TypeScript,它容易使用速度快速,可以直接反射.proto文件,不需要生成任何文件。
Google Protocol Buffers 传输的数据是二进制格式,JavaScript 天生不具备处理二进制数据的能力,所以要依赖 ByteBuffer.js ,ByteBuffer 和 ProtoBuf 都是由同一个团队 dcode.io 出品,ByteBuffer 可以单独使用,兼容 IE8+。
protobuf.js是基于ByteBuffer.js的Protocol Buffers纯JavaScript实现,主要功能是解析.proto文件,构建Message类,编码解码。
全局安装protobufjs,使用pbjs直接生成proto文件对应的js protobuf描述文件,这样就可以在普通页面中直接使用了。
安装
npm install protobufjs [--save --save-prefix=~]
使用
// 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'
手机预览