前端使用protobufjs,数据传输protobufjs使用记录
协议缓冲区是一种与语言无关的、与平台无关的、可扩展的序列化结构化数据的方法,用于通信协议、数据存储等,最初由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;
大概设置:
protobuf.js库很强大,可以继续研究一下。
文中的示例,最终使用的是base64,这样对ajax请求无影响,直接使用post请求,即可。如果直接用buffer,需要自己封装ajax;
大概设置:
xhr.responseType = 'blob'
同时使用protobuf.js,和后端使用规范版本要一致。
没有终点,没有彼岸,坚持就好,愿岁月如初