gpt4 book ai didi

angular - 如何在 gRPC Angular 应用程序中使用 typescript protobuf 生成的文件

转载 作者:行者123 更新时间:2023-12-03 17:32:49 26 4
gpt4 key购买 nike

总结问题

我正在学习如何使用 gRPC,并想尝试进行客户端-服务器连接。服务器(在 Elixir 中)工作正常,但我遇到了一些问题。但由于我主要是后端开发人员,在 Angular 中实现它时遇到了更多麻烦,希望能得到一些帮助。

我在这个项目中使用 Angular 8.2.9、Angular CLI 8.3.8 和 Node 10.16.0。

我已经做了什么?

  • 使用 ng new test-grpc 创建了一个新的 Angular cli 项目
  • ng g... 生成了一个模块和一个组件,并修改基本路由以具有工作页面和 url。
  • 已安装的 Protobuf 和 gRPC 库 npm install @improbable-eng/grpc-web @types/google-protobuf google-protobuf grpc-web-client protoc ts-protoc-gen --save
  • 拿了.proto从我的 Elixir 代码中提取文件并将其复制到文件夹 src/proto
  • 添加了 protoc package.json 中的命令 scripts :
    "protoc": "protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts.cmd --js_out=import_style=commonjs,binary:src/app/proto-gen --ts_out=service=true:src/app/proto-ts -I ./src/proto/ ./src/proto/*.proto"
  • 调用命令生成 src/app/proto-ts 中的 js 和 ts 文件和 src/app/proto-js
  • 替换任何 _-在生成的文件的名称中。
  • 然后我尝试在 ngOnInit 中添加以下代码:https://github.com/improbable-eng/grpc-web/tree/master/client/grpc-web#usage-overview如:

  • const getBookRequest = new GetBookRequest();
    getBookRequest.setIsbn(60929871);
    grpc.unary(BookService.GetBook, {
    request: getBookRequest,
    host: host,
    onEnd: res => {
    const { status, statusMessage, headers, message, trailers } = res;
    if (status === grpc.Code.OK && message) {
    console.log("all ok. got book: ", message.toObject());
    }
    }
    });

    我试过:
  • 在构造函数参数中创建请求。
  • 找到如何添加 typescript 文件(我只找到在 Angular 项目中添加javascript文件的方法,生成的javascript比 typescript 重得多,没有任何解释)。
  • 要了解 jspb.Message 是什么(我仍然不知道,但我认为它链接到此文件:https://github.com/protocolbuffers/protobuf/blob/master/js/message.js)
  • 试图找到有关如何在 Angular 应用程序中实现 rGPD 的教程(404 未找到)

  • .proto 文件、两个 typescript 生成的文件以及尝试使用它们的组件

    .proto 文件():

    // src/proto/user.proto
    syntax = "proto3";

    service UserService {
    rpc ListUsers (ListUsersRequest) returns (ListUsersReply);
    }

    message ListUsersRequest {
    string message = 1;
    }


    message ListUsersReply {
    repeated User users = 1;
    }

    message User {
    int32 id = 1;
    string firstname = 2;
    }

    typescript 生成的代码(2个文件):

    // src/app/proto-ts/user-pb.d.ts

    import * as jspb from "google-protobuf";

    export class ListUsersRequest extends jspb.Message {
    getMessage(): string;
    setMessage(value: string): void;

    serializeBinary(): Uint8Array;
    toObject(includeInstance?: boolean): ListUsersRequest.AsObject;
    static toObject(includeInstance: boolean, msg: ListUsersRequest): ListUsersRequest.AsObject;
    static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
    static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
    static serializeBinaryToWriter(message: ListUsersRequest, writer: jspb.BinaryWriter): void;
    static deserializeBinary(bytes: Uint8Array): ListUsersRequest;
    static deserializeBinaryFromReader(message: ListUsersRequest, reader: jspb.BinaryReader): ListUsersRequest;
    }

    export namespace ListUsersRequest {
    export type AsObject = {
    message: string,
    }
    }

    export class ListUsersReply extends jspb.Message {
    clearUsersList(): void;
    getUsersList(): Array<User>;
    setUsersList(value: Array<User>): void;
    addUsers(value?: User, index?: number): User;

    serializeBinary(): Uint8Array;
    toObject(includeInstance?: boolean): ListUsersReply.AsObject;
    static toObject(includeInstance: boolean, msg: ListUsersReply): ListUsersReply.AsObject;
    static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
    static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
    static serializeBinaryToWriter(message: ListUsersReply, writer: jspb.BinaryWriter): void;
    static deserializeBinary(bytes: Uint8Array): ListUsersReply;
    static deserializeBinaryFromReader(message: ListUsersReply, reader: jspb.BinaryReader): ListUsersReply;
    }

    export namespace ListUsersReply {
    export type AsObject = {
    usersList: Array<User.AsObject>,
    }
    }

    export namespace User {
    export type AsObject = {
    id: number,
    firstname: string,
    }
    }

    // src/app/proto-ts/user-pb-service.d.ts
    import * as user_pb from "./user-pb";
    import {grpc} from "@improbable-eng/grpc-web";

    type UserServiceListUsers = {
    readonly methodName: string;
    readonly service: typeof UserService;
    readonly requestStream: false;
    readonly responseStream: false;
    readonly requestType: typeof user_pb.ListUsersRequest;
    readonly responseType: typeof user_pb.ListUsersReply;
    };

    export class UserService {
    static readonly serviceName: string;
    static readonly ListUsers: UserServiceListUsers;
    }

    export type ServiceError = { message: string, code: number; metadata: grpc.Metadata }
    export type Status = { details: string, code: number; metadata: grpc.Metadata }
    interface UnaryResponse {
    cancel(): void;
    }
    interface ResponseStream<T> {
    cancel(): void;
    on(type: 'data', handler: (message: T) => void): ResponseStream<T>;
    on(type: 'end', handler: (status?: Status) => void): ResponseStream<T>;
    on(type: 'status', handler: (status: Status) => void): ResponseStream<T>;
    }
    interface RequestStream<T> {
    write(message: T): RequestStream<T>;
    end(): void;
    cancel(): void;
    on(type: 'end', handler: (status?: Status) => void): RequestStream<T>;
    on(type: 'status', handler: (status: Status) => void): RequestStream<T>;
    }
    interface BidirectionalStream<ReqT, ResT> {
    write(message: ReqT): BidirectionalStream<ReqT, ResT>;
    end(): void;
    cancel(): void;
    on(type: 'data', handler: (message: ResT) => void): BidirectionalStream<ReqT, ResT>;
    on(type: 'end', handler: (status?: Status) => void): BidirectionalStream<ReqT, ResT>;
    on(type: 'status', handler: (status: Status) => void): BidirectionalStream<ReqT, ResT>;
    }

    export class UserServiceClient {
    readonly serviceHost: string;

    constructor(serviceHost: string, options?: grpc.RpcOptions);
    listUsers(
    requestMessage: user_pb.ListUsersRequest,
    metadata: grpc.Metadata,
    callback: (error: ServiceError|null, responseMessage: user_pb.ListUsersReply|null) => void
    ): UnaryResponse;
    listUsers(
    requestMessage: user_pb.ListUsersRequest,
    callback: (error: ServiceError|null, responseMessage: user_pb.ListUsersReply|null) => void
    ): UnaryResponse;
    }

    尝试在组件文件中使用它们:

    // src/app/modules/user/pages/list/list.component.ts
    import { Component, OnInit } from '@angular/core';
    import { grpc } from "@improbable-eng/grpc-web";

    import { UserService } from '../../../../proto-ts/user-pb-service.d'
    import { ListUsersRequest } from '../../../../proto-ts/user-pb.d'

    @Component({
    selector: 'app-list',
    templateUrl: './list.component.html',
    styleUrls: ['./list.component.scss']
    })
    export class ListComponent implements OnInit {

    constructor() { }

    ngOnInit() {
    const listUsersRequest = new ListUsersRequest();
    listUsersRequest.setMessage("Hello world");

    grpc.unary(UserService.ListUsers, {
    request: listUsersRequest,
    host: "0.0.0.0:50051",
    onEnd: res => {
    const { status, statusMessage, headers, message, trailers } = res;
    if (status === grpc.Code.OK && message) {
    console.log("all ok. got the user list: ", message.toObject());
    } else {
    console.log("error");
    }
    }
    });
    }
    }

    预期结果和实际结果

    我希望能够在组件(或服务)中使用非 Angular typescript 代码。
    由于上面的代码(但组件文件)是生成的,所以不应该修改 ,因为 .proto 上的任何更改文件将覆盖在这两个生成的文件中所做的任何修改。

    目前,我被这两条错误消息阻止,这取决于我上次保存的文件: TypeError: _proto_ts_user_pb_d__WEBPACK_IMPORTED_MODULE_4__.ListUsersRequest is not a constructor (如果我最后保存了一个 protobuf 生成的文件,控制台中没有错误)或 src\app\proto-ts\user-pb-service.d.ts and src\app\proto-ts\user-pb.d.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property. (如果我最后保存了一个 Angular 文件,控制台中会出现相同的错误消息)。

    tsconfig.json 中添加"file"或“包含” (由 Angular CLI 生成,未经任何修改)创建另一个错误: Refused to load the image 'http://localhost:4200/favicon.ico' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.

    最佳答案

    我意识到这个问题很老,你已经解决了这个问题。
    但我想补充两点:

  • grpc-web 堆栈过于复杂。 protobuf JavaScript API 的文档很少,grpc-web 也好不到哪里去,在上面生成 TypeScript 声明只会让事情变得更糟。
  • 官方堆栈有替代品! ts-proto例如生成纯 TypeScript。

  • 我在 grpc web 和 Angular 方面有非常相似的经历并开始 protobuf-ts出于沮丧。它是一个生成 TypeScript 并支持 grpc-web 的 protoc-plugin。它是从头开始编写的,可能是一个可行的替代方案......

    关于angular - 如何在 gRPC Angular 应用程序中使用 typescript protobuf 生成的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58247650/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com