同样是要使用protobuf.js这个库来解析。
之前提到,在vue中,为了避免直接使用.proto文件,需要将所有的.proto打包成.js来使用。
而在node端,也可以打包成js文件来处理。但node端是服务端环境了,完全可以允许.proto的存在,所以其实我们可以有优雅的使用方式:直接解析。
封装两个基础模块:
在项目中可以这样使用:
// lib/api.js 封装API
const request = require('./request')
const proto = require('./proto')
/**
*
* @param {* 请求数据} params
* getStudentList 是接口名称
* school.PBStudentListRsp 是定义好的返回model
* school.PBStudentListReq 是定义好的请求体model
*/
exports.getStudentList = function getStudentList (params) {
const req = proto.create('school.PBStudentListReq', params)
return request('school.getStudentList', req, 'school.PBStudentListRsp')
}
// 项目中使用lib/api.js
const api = require('../lib/api')
const req = {
limit: 20,
offset: 0
}
api.getStudentList(req).then((res) => {
console.log(res)
}).catch(() => {
// ...
})
准备如何在前端中使用protobuf(vue篇)中定义好的一份.proto,注意这份proto中定义了两个命名空间:framework和school。proto文件源码
参考下官方文档将object转化为buffer的方法:
protobuf.load("awesome.proto", function(err, root) {
if (err)
throw err;
var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");
var payload = { awesomeField: "AwesomeString" };
var message = AwesomeMessage.create(payload);
var buffer = AwesomeMessage.encode(message).finish();
});
应该比较容易理解:先load awesome.proto,然后将数据payload转变成我们想要的buffer。create和encode都是protobufjs提供的方法。
如果我们的项目中只有一个.proto文件,我们完全可以像官方文档这样用。
但是在实际项目中,往往是有很多个.proto文件的,如果每个PBMessage都要先知道在哪个.proto文件中,使用起来会比较麻烦,所以需要封装一下。
服务端同学给我们的接口枚举中一般是这样的:
getStudentList = 0; // 获取所有学生的列表, PBStudentListReq => PBStudentListRsp
这里只告诉了这个接口的请求体是PBStudentListReq,返回值是PBStudentListRsp,而它们所在的.proto文件是不知道的。
为了使用方便,我们希望封装一个方法,形如:
const reqBuffer = proto.create('school.PBStudentListReq', dataObj)
我们使用时只需要以PBStudentListReq和dataObj作为参数即可,无需关心PBStudentListReq是在哪个.proto文件中。
这里有个难点:如何根据类型来找到所在的.proto呢?
方法是:把所有的.proto放进内存中,然后根据名称获取对应的类型。
写一个loadProtoDir方法,把所有的proto保存在_proto变量中。
// proto.js
const fs = require('fs')
const path = require('path')
const ProtoBuf = require('protobufjs')
let _proto = null
// 将所有的.proto存放在_proto中
function loadProtoDir (dirPath) {
const files = fs.readdirSync(dirPath)
const protoFiles = files
.filter(fileName => fileName.endsWith('.proto'))
.map(fileName => path.join(dirPath, fileName))
_proto = ProtoBuf.loadSync(protoFiles).nested
return _proto
}
_proto类似一颗树,我们可以遍历这棵树找到具体的类型,也可以通过其他方法直接获取,比如lodash.get()方法,它支持obj['xx.xx.xx']这样的形式来取值。
const _ = require('lodash')
const PBMessage = _.get(_proto, 'school.PBStudentListReq')
这样我们就拿到了顺利地根据类型在所有的proto获取到了PBMessage,PBMessage中会有protobuf.js提供的create、encode等方法,我们可以直接利用并将object转成buffer。
const reqData = {a: '1'}
const message = PBMessage.create(reqData)
const reqBuffer = PBMessage.encode(message).finish()
整理一下,为了后面使用方便,封装成三个函数:
let _proto = null
// 将所有的.proto存放在_proto中
function loadProtoDir (dirPath) {
const files = fs.readdirSync(dirPath)
const protoFiles = files
.filter(fileName => fileName.endsWith('.proto'))
.map(fileName => path.join(dirPath, fileName))
_proto = ProtoBuf.loadSync(protoFiles).nested
return _proto
}
// 根据typeName获取PBMessage
function lookup (typeName) {
if (!_.isString(typeName)) {
throw new TypeError('typeName must be a string')
}
if (!_proto) {
throw new TypeError('Please load proto before lookup')
}
return _.get(_proto, typeName)
}
function create (protoName, obj) {
// 根据protoName找到对应的message
const model = lookup(protoName)
if (!model) {
throw new TypeError(`${protoName} not found, please check it again`)
}
const req = model.create(obj)
return model.encode(req).finish()
}
module.exports = {
lookup, // 这个方法将在request中会用到
create,
loadProtoDir
}
这里要求,在使用create和lookup前,需要先loadProtoDir,将所有的proto都放进内存。
这里要建议先看一下MessageType.proto,其中定义了与后端约定的接口枚举、请求体、响应体。
const rp = require('request-promise')
const proto = require('./proto.js') // 上面我们封装好的proto.js
/**
*
* @param {* 接口名称} msgType
* @param {* proto.create()后的buffer} requestBody
* @param {* 返回类型} responseType
*/
function request (msgType, requestBody, responseType) {
// 得到api的枚举值
const _msgType = proto.lookup('framework.PBMessageType')[msgType]
// PBMessageRequest是公共请求体,携带一些额外的token等信息,后端通过type获得接口名称,messageData获得请求数据
const PBMessageRequest = proto.lookup('framework.PBMessageRequest')
const req = PBMessageRequest.encode({
timeStamp: new Date().getTime(),
type: _msgType,
version: '1.0',
messageData: requestBody,
token: 'xxxxxxx'
}).finish()
// 发起请求,在vue中我们可以使用axios发起ajax,但node端需要换一个,比如"request"
// 我这里推荐使用一个不错的库:"request-promise",它支持promise
const options = {
method: 'POST',
uri: 'http://your_server.com/api',
body: req,
encoding: null,
headers: {
'Content-Type': 'application/octet-stream'
}
}
return rp.post(options).then((res) => {
// 解析二进制返回值
const decodeResponse = proto.lookup('framework.PBMessageResponse').decode(res)
const { resultInfo, resultCode } = decodeResponse
if (resultCode === 0) {
// 进一步解析解析PBMessageResponse中的messageData
const model = proto.lookup(responseType)
let msgData = model.decode(decodeResponse.messageData)
return msgData
} else {
throw new Error(`Fetch ${msgType} failed.`)
}
})
}
module.exports = request
request.js和proto.js提供底层的服务,为了使用方便,我们还要封装一个api.js,定义项目中所有的api。
const request = require('./request')
const proto = require('./proto')
exports.getStudentList = function getStudentList (params) {
const req = proto.create('school.PBStudentListReq', params)
return request('school.getStudentList', req, 'school.PBStudentListRsp')
}
在项目中使用接口时,只需要require('lib/api'),不直接引用proto.js和request.js。
// test.js
const api = require('../lib/api')
const req = {
limit: 20,
offset: 0
}
api.getStudentList(req).then((res) => {
console.log(res)
}).catch(() => {
// ...
})
原文:https://segmentfault.com/a/1190000021052359
一项名为 JavaScript 功能的提案 Array.prototype.flatten 证明与 Web 不兼容。在 Firefox Nightly 中发布该功能会导致至少一个受欢迎的网站中断。鉴于有问题的代码是广泛使用的 MooTools 库的一部分,很可能会有更多网站受到影响。
让你了解到新兴和酷炫的web 开发趋势. 精心挑选发布一些认为大家值得关注的库:Direction Reveal、Carbon、Аxios、Jarvis、Toast UI Editor、Micron.js、lit
math.js是一个广泛应用于JavaScript 和 Node.js的数学库,它的特点是灵活表达式解析器,支持符号计算,内置大量函数与常量,并提供集成解决方案来处理不同的数据类型,如数字,大数字,复数,分数,单位和矩阵。
当你调研一个 JS 库,功能当然是最重要的。作者给出了从 12 个角度全面分析 JS 库的可用性,分别是:特性,稳定性,性能,包生态,社区,学习曲线,文档,工具,发展历史,团队,兼容性,趋势
对于今年的JavaScript状态调查,我想深入挖掘一下,不仅知道人们正在使用哪些工具和库,还要为什么他们选择使用它们。这意味着我必须找到一种方法将个人偏好转化为冷酷的数据。
本篇 React native 库列表不是从网上随便找的, 这些是我在我的应用中亲自使用的库。 这些库功能可能跟其它库也有,但经过大量研究并在我的程序中尝试后,我选择了这些库。
我们的使命是让您了解最新和最酷的Web开发趋势。下面为大家分享10个有趣的javascript和css库:Tessaract.js强大的javascript(节点和浏览器)库,用于从图像中提取文本。
在javascript的帮助下,可以为几乎每个领域(如移动、桌面应用程序和游戏Web开发)创建Web应用程序,因为该编程语言用作服务器端编程语言以实现最大功能,所以它是一种很好的编程语言。在本文中,我们选择了一些最佳的javascript库汇总
当我想要在网上找一个简洁的 Javascript 动效库时,总是发现很多“推荐”的库都是缺乏持续维护的。经过一番研究,我收集了 11 个最好的库,你可以用在自己的项目中。另外我还添加了一些有用但是缺少持续维护的库
如今 Vue 的热度不断攀升,使用者越来越多,Vue.js 工具也随处可见。这种现象不是凭空产生的:Vue 的学习曲线友好,功能驱动的结构清晰易懂,文档出色易学,所以新人入门很容易,经验丰富的开发人员也可以快速从其他框架
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!