vue + .net core + grpc-web

环境准备

  1. 下载插件protoc-gen-grpc-web,下载完成后重名文件为protoc-gen-grpc-web.exe
  2. 下载grpc,下载完成后解压文件。
  3. protoc-gen-grpc-web.exe所在目录和grpcbin目录添加到系统环境变量中。

这里需要特别说明的是grpc的版本号不能高于3.20.1,否则在根据proto生成js文件的时候控制台会报protoc-gen-js不是内部命令的错误。

.Net Core(3.1)

创建grpc服务端项目

  1. 启动 Visual Studio 2022 并选择“创建新项目”。
  2. 在“创建新项目”对话框中,搜索 gRPC。 选择“ASP.NET Core gRPC 服务”,并选择“下一步” 。
  3. 在“配置新项目”对话框中,为“项目名称”输入 GrpcGreeter。
  4. 选择“下一页”。
  5. 在“其他信息”对话框中,选择“.NET 3.1 (长期支持)”,然后选择“创建”。

配置 ASP.NET Core 中的 gRPC-Web

  1. 右键GrpcGreeter项目的依赖项,选择管理NuGet程序包,搜做Grpc.AspNetCore.Web并安装。
  2. 配置StartUp.cs文件
public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
    // 跨域配置
    services.AddCors(o => o.AddPolicy("AllowAll", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader()
               .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
    }));
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseGrpcWeb(); // 在路由之后、终结点之前添加 gRPC-Web 中间件 UseGrpcWeb。
    app.UseCors();   // 启用跨域中间件

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>()
		.EnableGrpcWeb()  // 指定 endpoints.MapGrpcService<GreeterService>() 方法支持带有 EnableGrpcWeb 的 gRPC-Web。
		.RequireCors("AllowAll");  // 指定 endpoints.MapGrpcService<GreeterService>() 方法支持带有 RequiresCors的 CORS。
    });
}
  1. 修改 greet.proto
syntax = "proto3";

option csharp_namespace = "GrpcGreeter";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
  rpc SayHellos (HelloRequest) returns (stream HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

  1. 修改 GreeterService.cs
using Grpc.Core;
using System;
using System.Threading.Tasks;

namespace GrpcGreeter
{
    public class GreeterService : Greeter.GreeterBase
    {
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }

        public override async Task SayHellos(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
        {
            var i = 0;
            while (!context.CancellationToken.IsCancellationRequested)
            {
                await responseStream.WriteAsync(new HelloReply { Message = $"Hello {request.Name} {i}" });
                await Task.Delay(TimeSpan.FromSeconds(1));
                i++;
            }
        }
    }
}

在 Vue 中使用grpc-web

  1. 新建vue2项目
  2. 安装依赖包 npm i google-protobuf grpc-web
  3. 在后台程序的greet.proto目录下执行编译命令 protoc greet.proto --js_out=import_style=commonjs:.\ --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.\,复制生成的文件greet_grpc_web_pb.jsgreet_pb.js到前端项目中。
  4. 修改App.vue代码:
<template>
  <div id="app">
    <h2>gRPC-Web ASP.NET Core example</h2>
    <div>
      <span>Hello:</span>
      <input id="name" type="text" v-model="name" />
      <button @click="sendUnary" :disabled="unaryDisabled">Send unary</button>
      <button @click="startServerStream">{{ btnText }}</button>
    </div>
    <p id="result" v-html="result"></p>
  </div>
</template>

<script>
import { HelloRequest } from "./pb/greet_pb";
import { GreeterClient } from "./pb/greet_grpc_web_pb";
let streamingCall = null;
export default {
  data() {
    return {
      client: null,
      result: "",
      name: "",
      unaryDisabled: false,
      btnText: "Start server stream",
    };
  },
  created() {
    this.client = new GreeterClient("https://localhost:5001");
  },
  methods: {
    sendUnary() {
      let request = new HelloRequest();
      request.setName(this.name);

      this.client.sayHello(request, {}, (err, response) => {
        this.result = response.getMessage();
      });
    },
    startServerStream() {
      if (!streamingCall) {
        this.unaryDisabled = true;
        this.btnText = "Stop server stream";
        this.result = "";

        var request = new HelloRequest();
        request.setName(this.name);

        streamingCall = this.client.sayHellos(request, {});
        streamingCall.on("data", (response) => {
          this.result += response.getMessage() + "<br />";
        });
        streamingCall.on("status", (status) => {
          if (status.code == 0) {
            this.result += "Done";
          } else {
            this.result += "Error: " + status.details;
          }
        });
      } else {
        streamingCall.cancel();
        streamingCall = null;
        this.unaryDisabled = false;
        this.btnText = "Start server stream";
      }
    },
  },
};
</script>

<style lang="scss">
#app {
  * + * {
    margin-left: 20px;
  }
}
</style>


参考文章:

在浏览器应用中使用 gRPC
gRPC-Web 编写 JavaScript 客户端代码。

posted @ 2022-07-29 13:15  吉喆吉  阅读(696)  评论(0编辑  收藏  举报