分享
  1. 首页
  2. 文章

Angular2+ 使用 Protocol Buffers

旅行时序 · · 1714 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

just do it

最近在写一个web IM 项目,虽然本人主打golang后端,但是部分前端还是需要自己解决。因为这是一个IM系统,所以不考虑使用json来传送数据,改用protocol buffers ,优点见官网。由于前端不太熟练,经常被Angular坑,包括这次,花费我一个下午时间来解决Angular2+ 使用 Protocol Buffers的问题。
灵感来源:Using protocol buffers with Node.js + Swagger + Angular

进入正题,本机环境 Linux ubuntu

1. 定义一个简单的 .proto 文件

具体的protocol buffers 的.proto文件定义见官网,下面展现一个简单的小例子:

// Protocol.proto
syntax="proto3";
package Protocol; 
message C2CSendRequest{
 int64 from = 1; //发送者
 int64 to = 2; //接受者
 string content = 3 ; //消息内容
}

2.生成 .js 和 .d.ts 文件

首先使用npm命令 安装 protobuf.js:

npm install protobufjs

然后你会得到 pbjspbts 这两个命令 [注意下面!有坑!]
这两个命令都在 node_modules/protobufjs/cli/bin/ 路径底下(看清楚这路径有cli),你如果不知道在哪里的话

执行 sudo find / -name pbjs

得到下面的输出

pjw@O-E-M:~$ sudo find / -name pbjs
find: ‘/tmp/.mount_Shadowl3Qfnt’: 权限不够
/usr/local/node-v10.15.0-linux-x64/bin/pbjs
/usr/local/node-v10.15.0-linux-x64/lib/node_modules/pbjs
/home/pjw/node_modules/.bin/pbjs
/home/pjw/node_modules/protobufjs/bin/pbjs
/home/pjw/node_modules/protobufjs/cli/bin/pbjs <===就是这个目录的 pbjs,不是别的目录。(注意这个/home/pjw是我的家目录目录)
/home/pjw/.local/share/Trash/files/protobuf.2.js/cli/bin/pbjs
/home/pjw/.local/share/Trash/files/protobuf.js/bin/pbjs
/home/pjw/.local/share/Trash/files/protobuf.js/cli/bin/pbjs

这目录底下的两个命令还是不可以执行的,在这个目录底下执行:

sudo chmod a+x pbjs
sudo chmod a+x pbts

先说一下我在这里遇到的坑:如果刚执行完 npm install protobufjs ,马上执行 pbjs 命令,这条命令是不正确的,并且你执行 pbts 会显示找不到命令。而正确的命令是在 node_modules/protobufjs/cli/bin/底下。

正式开始生成.js 和 .d.ts 文件:

../node_modules/protobufjs/cli/bin/pbjs -t static-module -w commonjs -o Protocol.js Protocol.proto
../node_modules/protobufjs/cli/bin/pbts -o Protocol.d.ts Protocol.js

分别生成 Protocol.js 和 Protocol.d.ts 。
这时候 Protocol.d.ts 文件有些错误,Cannot find name 'Long', 原因是 .proto 文件有些字段是 int64 类型 。
解决办法 在Protocol.d.ts 文件第二行插入 :

import {Long} from "protobufjs";

那么现在 js和 .d.ts 声明文件也有了,那如何在Angular上使用。

3. protobuf 在Angular 简单使用

简单的测试一下是否可以再Angular上面使用,更复杂的使用待学习。

import { Injectable } from '@angular/core';
import { Protocol } from "./Protocol"; <====引入模块
@Injectable()
export class TestService {
 request: Protocol.C2CSendRequest = new(Protocol.C2CSendRequest); <=== new 一个 message
 constructor() { }
 test(){
 this.request.content="dasdasdas"; <===使用它
 this.request.from=1;
 this.request.msgid=222;
 this.request.timestamp=231412;
 console.log(this.request)
 }
}

4.总结

其实在这篇文章灵感来源:Using protocol buffers with Node.js + Swagger + Angular讲的很详细,是我大部分的借鉴来源。虽然一开始搜到这篇文章,但是因为是英文没有详细阅读,而是随意浏览,错过这个解决办法。幸好师姐帮我解决问题的时候,把这篇文章再看一遍,才发现里面的解决方案。其中一直困扰着我的问题就是: 为什么我的 pbjs 生成的js文件和别人的生成js文件不一样,即使是.proto文件相同。最后是发现 是node_modules/protobufjs/cli/bin目录底下的命令才是真正需要的命令。

5.补充

Protocol.js 文件内容:

/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
"use strict";
var $protobuf = require("protobufjs/minimal");
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// Exported root namespace
var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
$root.Protocol = (function() {
 /**
 * Namespace Protocol.
 * @exports Protocol
 * @namespace
 */
 var Protocol = {};
 Protocol.C2CSendRequest = (function() {
 /**
 * Properties of a C2CSendRequest.
 * @memberof Protocol
 * @interface IC2CSendRequest
 * @property {number|Long|null} [from] C2CSendRequest from
 * @property {number|Long|null} [to] C2CSendRequest to
 * @property {string|null} [content] C2CSendRequest content
 */
 /**
 * Constructs a new C2CSendRequest.
 * @memberof Protocol
 * @classdesc Represents a C2CSendRequest.
 * @implements IC2CSendRequest
 * @constructor
 * @param {Protocol.IC2CSendRequest=} [properties] Properties to set
 */
 function C2CSendRequest(properties) {
 if (properties)
 for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
 if (properties[keys[i]] != null)
 this[keys[i]] = properties[keys[i]];
 }
 /**
 * C2CSendRequest from.
 * @member {number|Long} from
 * @memberof Protocol.C2CSendRequest
 * @instance
 */
 C2CSendRequest.prototype.from = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
 /**
 * C2CSendRequest to.
 * @member {number|Long} to
 * @memberof Protocol.C2CSendRequest
 * @instance
 */
 C2CSendRequest.prototype.to = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
 /**
 * C2CSendRequest content.
 * @member {string} content
 * @memberof Protocol.C2CSendRequest
 * @instance
 */
 C2CSendRequest.prototype.content = "";
 /**
 * Creates a new C2CSendRequest instance using the specified properties.
 * @function create
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Protocol.IC2CSendRequest=} [properties] Properties to set
 * @returns {Protocol.C2CSendRequest} C2CSendRequest instance
 */
 C2CSendRequest.create = function create(properties) {
 return new C2CSendRequest(properties);
 };
 /**
 * Encodes the specified C2CSendRequest message. Does not implicitly {@link Protocol.C2CSendRequest.verify|verify} messages.
 * @function encode
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Protocol.IC2CSendRequest} message C2CSendRequest message or plain object to encode
 * @param {$protobuf.Writer} [writer] Writer to encode to
 * @returns {$protobuf.Writer} Writer
 */
 C2CSendRequest.encode = function encode(message, writer) {
 if (!writer)
 writer = $Writer.create();
 if (message.from != null && message.hasOwnProperty("from"))
 writer.uint32(/* id 1, wireType 0 =*/8).int64(message.from);
 if (message.to != null && message.hasOwnProperty("to"))
 writer.uint32(/* id 2, wireType 0 =*/16).int64(message.to);
 if (message.content != null && message.hasOwnProperty("content"))
 writer.uint32(/* id 3, wireType 2 =*/26).string(message.content);
 return writer;
 };
 /**
 * Encodes the specified C2CSendRequest message, length delimited. Does not implicitly {@link Protocol.C2CSendRequest.verify|verify} messages.
 * @function encodeDelimited
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Protocol.IC2CSendRequest} message C2CSendRequest message or plain object to encode
 * @param {$protobuf.Writer} [writer] Writer to encode to
 * @returns {$protobuf.Writer} Writer
 */
 C2CSendRequest.encodeDelimited = function encodeDelimited(message, writer) {
 return this.encode(message, writer).ldelim();
 };
 /**
 * Decodes a C2CSendRequest message from the specified reader or buffer.
 * @function decode
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
 * @param {number} [length] Message length if known beforehand
 * @returns {Protocol.C2CSendRequest} C2CSendRequest
 * @throws {Error} If the payload is not a reader or valid buffer
 * @throws {$protobuf.util.ProtocolError} If required fields are missing
 */
 C2CSendRequest.decode = function decode(reader, length) {
 if (!(reader instanceof $Reader))
 reader = $Reader.create(reader);
 var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Protocol.C2CSendRequest();
 while (reader.pos < end) {
 var tag = reader.uint32();
 switch (tag >>> 3) {
 case 1:
 message.from = reader.int64();
 break;
 case 2:
 message.to = reader.int64();
 break;
 case 3:
 message.content = reader.string();
 break;
 default:
 reader.skipType(tag & 7);
 break;
 }
 }
 return message;
 };
 /**
 * Decodes a C2CSendRequest message from the specified reader or buffer, length delimited.
 * @function decodeDelimited
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
 * @returns {Protocol.C2CSendRequest} C2CSendRequest
 * @throws {Error} If the payload is not a reader or valid buffer
 * @throws {$protobuf.util.ProtocolError} If required fields are missing
 */
 C2CSendRequest.decodeDelimited = function decodeDelimited(reader) {
 if (!(reader instanceof $Reader))
 reader = new $Reader(reader);
 return this.decode(reader, reader.uint32());
 };
 /**
 * Verifies a C2CSendRequest message.
 * @function verify
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Object.<string,*>} message Plain object to verify
 * @returns {string|null} `null` if valid, otherwise the reason why it is not
 */
 C2CSendRequest.verify = function verify(message) {
 if (typeof message !== "object" || message === null)
 return "object expected";
 if (message.from != null && message.hasOwnProperty("from"))
 if (!$util.isInteger(message.from) && !(message.from && $util.isInteger(message.from.low) && $util.isInteger(message.from.high)))
 return "from: integer|Long expected";
 if (message.to != null && message.hasOwnProperty("to"))
 if (!$util.isInteger(message.to) && !(message.to && $util.isInteger(message.to.low) && $util.isInteger(message.to.high)))
 return "to: integer|Long expected";
 if (message.content != null && message.hasOwnProperty("content"))
 if (!$util.isString(message.content))
 return "content: string expected";
 return null;
 };
 /**
 * Creates a C2CSendRequest message from a plain object. Also converts values to their respective internal types.
 * @function fromObject
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Object.<string,*>} object Plain object
 * @returns {Protocol.C2CSendRequest} C2CSendRequest
 */
 C2CSendRequest.fromObject = function fromObject(object) {
 if (object instanceof $root.Protocol.C2CSendRequest)
 return object;
 var message = new $root.Protocol.C2CSendRequest();
 if (object.from != null)
 if ($util.Long)
 (message.from = $util.Long.fromValue(object.from)).unsigned = false;
 else if (typeof object.from === "string")
 message.from = parseInt(object.from, 10);
 else if (typeof object.from === "number")
 message.from = object.from;
 else if (typeof object.from === "object")
 message.from = new $util.LongBits(object.from.low >>> 0, object.from.high >>> 0).toNumber();
 if (object.to != null)
 if ($util.Long)
 (message.to = $util.Long.fromValue(object.to)).unsigned = false;
 else if (typeof object.to === "string")
 message.to = parseInt(object.to, 10);
 else if (typeof object.to === "number")
 message.to = object.to;
 else if (typeof object.to === "object")
 message.to = new $util.LongBits(object.to.low >>> 0, object.to.high >>> 0).toNumber();
 if (object.content != null)
 message.content = String(object.content);
 return message;
 };
 /**
 * Creates a plain object from a C2CSendRequest message. Also converts values to other types if specified.
 * @function toObject
 * @memberof Protocol.C2CSendRequest
 * @static
 * @param {Protocol.C2CSendRequest} message C2CSendRequest
 * @param {$protobuf.IConversionOptions} [options] Conversion options
 * @returns {Object.<string,*>} Plain object
 */
 C2CSendRequest.toObject = function toObject(message, options) {
 if (!options)
 options = {};
 var object = {};
 if (options.defaults) {
 if ($util.Long) {
 var long = new $util.Long(0, 0, false);
 object.from = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
 } else
 object.from = options.longs === String ? "0" : 0;
 if ($util.Long) {
 var long = new $util.Long(0, 0, false);
 object.to = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
 } else
 object.to = options.longs === String ? "0" : 0;
 object.content = "";
 }
 if (message.from != null && message.hasOwnProperty("from"))
 if (typeof message.from === "number")
 object.from = options.longs === String ? String(message.from) : message.from;
 else
 object.from = options.longs === String ? $util.Long.prototype.toString.call(message.from) : options.longs === Number ? new $util.LongBits(message.from.low >>> 0, message.from.high >>> 0).toNumber() : message.from;
 if (message.to != null && message.hasOwnProperty("to"))
 if (typeof message.to === "number")
 object.to = options.longs === String ? String(message.to) : message.to;
 else
 object.to = options.longs === String ? $util.Long.prototype.toString.call(message.to) : options.longs === Number ? new $util.LongBits(message.to.low >>> 0, message.to.high >>> 0).toNumber() : message.to;
 if (message.content != null && message.hasOwnProperty("content"))
 object.content = message.content;
 return object;
 };
 /**
 * Converts this C2CSendRequest to JSON.
 * @function toJSON
 * @memberof Protocol.C2CSendRequest
 * @instance
 * @returns {Object.<string,*>} JSON object
 */
 C2CSendRequest.prototype.toJSON = function toJSON() {
 return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
 };
 return C2CSendRequest;
 })();
 return Protocol;
})();
module.exports = $root;

Protocol.d.ts 文件内容:

import * as $protobuf from "protobufjs";
import {Long} from "protobufjs";
/** Namespace Protocol. */
export namespace Protocol {
 /** Properties of a C2CSendRequest. */
 interface IC2CSendRequest {
 /** C2CSendRequest from */
 from?: (number|Long|null);
 /** C2CSendRequest to */
 to?: (number|Long|null);
 /** C2CSendRequest content */
 content?: (string|null);
 }
 /** Represents a C2CSendRequest. */
 class C2CSendRequest implements IC2CSendRequest {
 /**
 * Constructs a new C2CSendRequest.
 * @param [properties] Properties to set
 */
 constructor(properties?: Protocol.IC2CSendRequest);
 /** C2CSendRequest from. */
 public from: (number|Long);
 /** C2CSendRequest to. */
 public to: (number|Long);
 /** C2CSendRequest content. */
 public content: string;
 /**
 * Creates a new C2CSendRequest instance using the specified properties.
 * @param [properties] Properties to set
 * @returns C2CSendRequest instance
 */
 public static create(properties?: Protocol.IC2CSendRequest): Protocol.C2CSendRequest;
 /**
 * Encodes the specified C2CSendRequest message. Does not implicitly {@link Protocol.C2CSendRequest.verify|verify} messages.
 * @param message C2CSendRequest message or plain object to encode
 * @param [writer] Writer to encode to
 * @returns Writer
 */
 public static encode(message: Protocol.IC2CSendRequest, writer?: $protobuf.Writer): $protobuf.Writer;
 /**
 * Encodes the specified C2CSendRequest message, length delimited. Does not implicitly {@link Protocol.C2CSendRequest.verify|verify} messages.
 * @param message C2CSendRequest message or plain object to encode
 * @param [writer] Writer to encode to
 * @returns Writer
 */
 public static encodeDelimited(message: Protocol.IC2CSendRequest, writer?: $protobuf.Writer): $protobuf.Writer;
 /**
 * Decodes a C2CSendRequest message from the specified reader or buffer.
 * @param reader Reader or buffer to decode from
 * @param [length] Message length if known beforehand
 * @returns C2CSendRequest
 * @throws {Error} If the payload is not a reader or valid buffer
 * @throws {$protobuf.util.ProtocolError} If required fields are missing
 */
 public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Protocol.C2CSendRequest;
 /**
 * Decodes a C2CSendRequest message from the specified reader or buffer, length delimited.
 * @param reader Reader or buffer to decode from
 * @returns C2CSendRequest
 * @throws {Error} If the payload is not a reader or valid buffer
 * @throws {$protobuf.util.ProtocolError} If required fields are missing
 */
 public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Protocol.C2CSendRequest;
 /**
 * Verifies a C2CSendRequest message.
 * @param message Plain object to verify
 * @returns `null` if valid, otherwise the reason why it is not
 */
 public static verify(message: { [k: string]: any }): (string|null);
 /**
 * Creates a C2CSendRequest message from a plain object. Also converts values to their respective internal types.
 * @param object Plain object
 * @returns C2CSendRequest
 */
 public static fromObject(object: { [k: string]: any }): Protocol.C2CSendRequest;
 /**
 * Creates a plain object from a C2CSendRequest message. Also converts values to other types if specified.
 * @param message C2CSendRequest
 * @param [options] Conversion options
 * @returns Plain object
 */
 public static toObject(message: Protocol.C2CSendRequest, options?: $protobuf.IConversionOptions): { [k: string]: any };
 /**
 * Converts this C2CSendRequest to JSON.
 * @returns JSON object
 */
 public toJSON(): { [k: string]: any };
 }
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:旅行时序

查看原文:Angular2+ 使用 Protocol Buffers

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1714 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏