aierda 2023-03-28 11:22 采纳率: 79.2%
浏览 38
已结题

使用grpc遇到的问题

问题描述:
我参考了关于grpc双向流的技术文章,网址为

之后,建立了一个控制台项目作为grpc请求发起请求的客户端,并且建立
了一个web项目作为接收请求的服务端,测试成功,两边可以相互通讯。
然后
我另外新建一个web项目,希望将其代替前面建立的控制台项目,作为
grpc请求发起请求的客户端,也就是说grpc的客户端和服务端都是web项目
,但是却出现了问题:
客户端发起请求时报“Status(StatusCode="Internal", Detail="Request protocol 'HTTP/1.1' is not supported.")”
这样的错误。
我们知道grpc是通过http/2进行通讯的,难道两个web端之间不能使用http/2进行通讯?
我百度了一下,似乎有个叫gRPC-Web的东西可以解决这个问题,是不是客户端和服务端
都需要gRPC-Web进行封装呢,还是只是服务端?

上面提到参考文章有源码可下,地址为https://github.com/stulzq/BlogDemos

img

提问:各位能人是否有遇到我这种情况, 请求解决方案和经验指点,期待大伙的意见,感谢!

  • 写回答

5条回答 默认 最新

  • 叶秋学长 全栈领域优质创作者 2023-03-28 20:37
    关注

    基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦💕(最新版更智能,功能更加强大):
    您的问题可能是由于两个Web项目之间使用了HTTP/1.1协议导致的,而gRPC需要使用HTTP/2协议才能正常工作。可以尝试在两个Web项目中使用HTTP/2协议来解决这个问题。

    可以使用gRPC-Web将gRPC请求转换为HTTP/1.1或HTTP/2请求,并在Web浏览器中使用JavaScript编写gRPC客户端代码。在这种情况下,您需要修改客户端代码以使用gRPC-Web。您可以使用如下命令来生成gRPC-Web代码:

    protoc --plugin=protoc-gen-grpc-web=/usr/local/bin/grpc-web-proxy \
           --grpc-web_out=import_style=commonjs,mode=grpcwebtext:./ \
           path/to/your.proto
    
    

    此外,您还需要在Web项目中安装并配置gRPC-Web代理,以便将gRPC请求转换为HTTP/1.1或HTTP/2请求。对于Java Web项目,您可以使用grpc-web-java库提供的gRPC-Web代理。

    如果您不想使用gRPC-Web,也可以尝试使用WebSocket协议来实现双向通信。WebSocket协议可以在Web浏览器和服务器之间建立持久性的双向连接,并支持二进制数据传输。在这种情况下,您需要使用WebSocket库来实现gRPC客户端和服务器。例如,您可以使用grpc-websocket-proxy来实现gRPC客户端和服务器之间的通信。

    综上所述,您可以尝试使用gRPC-Web或WebSocket来实现两个Web项目之间的双向通信。如果您有其他问题或需要更多帮助,请随时提问。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
  • 小逸2023 2023-03-28 11:36
    关注
    该回答引用ChatGPT
    根据问题描述,您的情况是想要将原本的控制台项目作为grpc请求发起请求的客户端替换成web项目,但是在新建的web项目中发起请求时出现了错误。
    错误信息为“Status(StatusCode="Internal", Detail="Request protocol 'HTTP/1.1' is not supported.")”,这个错误提示表明请求协议不支持,grpc是通过http/2进行通讯的,而您的请求协议是HTTP/1.1,因此出现了错误。
    解决这个问题的方法是使用gRPC-Web进行封装,gRPC-Web是一个支持在Web浏览器中使用gRPC的开源项目,它可以将gRPC请求转换为HTTP/1.1或HTTP/2请求,从而在Web浏览器中使用gRPC。
    在使用gRPC-Web时,需要在客户端和服务端都进行封装。具体实现可以参考以下步骤:
    1. 在服务端使用gRPC-Web进行封装
    在服务端,需要使用gRPC-Web进行封装,以便能够接收来自Web浏览器的gRPC请求。具体实现可以参考以下步骤:
    - 安装gRPC-Web
    可以使用以下命令安装gRPC-Web:

    npm install grpc-web

    - 修改服务端代码
    在服务端代码中,需要将原本的gRPC服务封装成gRPC-Web服务。具体实现可以参考以下代码:
    javascript
    const grpc = require('grpc');
    const grpcWeb = require('grpc-web');
    const proto = grpc.load('path/to/your/proto/file.proto');
    const server = new grpcWeb.WrappedGrpcServer({
    proto,
    // your gRPC service implementation
    implementation: {
    // your gRPC service methods
    },
    // your gRPC service options
    options: {
    // your gRPC service options
    },
    });
    server.start();

    2. 在客户端使用gRPC-Web进行封装
    在客户端,需要使用gRPC-Web进行封装,以便能够向服务端发送gRPC请求。具体实现可以参考以下步骤:
    - 安装gRPC-Web
    可以使用以下命令安装gRPC-Web:

    npm install grpc-web

    - 修改客户端代码
    在客户端代码中,需要使用gRPC-Web客户端来发送gRPC请求。具体实现可以参考以下代码:
    javascript
    const {HelloRequest, HelloReply} = require('path/to/your/proto/file_pb.js');
    const {GreeterClient} = require('path/to/your/proto/file_grpc_web_pb.js');
    const client = new GreeterClient('http://localhost:8080');
    const request = new HelloRequest();
    request.setName('World');
    client.sayHello(request, {}, (err, response) => {
    if (err) {
    console.error(err);
    } else {
    console.log(response.getMessage());
    }
    });

    以上是使用gRPC-Web进行封装的基本步骤,具体实现可能会因为您的项目结构和代码实现方式而有所不同。建议您参考gRPC-Web的官方文档和示例代码,以便更好地理解和实现gRPC-Web。
    评论
  • Huouayi 2023-03-28 12:04
    关注

    1、客户端添加 Grpc.Net.Client NuGet 包
    2、服务端添加 Grpc.AspNetCore NuGet 包
    3、客户端创建GrpcChannel 实例,再创建gRPC 客户端

    using Grpc.Net.Client;
    
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greeter.GreeterClient(channel);
    

    4、服务端创建gRPC 服务,在 Startup.cs 中把它添加到应用程序中

    using Grpc.Core;
    
    public class GreeterService : Greeter.GreeterBase
    {
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }
    
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseRouting();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<GreeterService>();
            });
        }
    }
    
    评论
  • 蓝白、波罗歌 2023-03-28 13:06
    关注

    以下答案由GPT-3.5大模型与博主波罗歌共同编写:
    从错误信息中可以看出,问题是客户端请求所用的协议不被支持。这是因为前面建立的控制台项目使用了grpc的原生客户端,而在新建的web项目中,使用的是HTTP客户端,因为http客户端只支持HTTP协议,而grpc需要使用http/2进行通讯。

    要解决这个问题,可以使用gRPC-Web技术,它允许在web上使用grpc,具体来说,gRPC-Web在客户端和浏览器之间提供了一个网关来转换http/1.1为grpc-web,它可以让grpc在浏览器中运行。

    在使用gRPC-Web之前,需要先启用gRPC-Web代理,而在服务端上,则不需要额外的处理,因为服务端的grpc实现是不变的。

    详细步骤如下:

    1. 在服务端添加gRPC-Web代理

    可以使用Envoy或nginx等代理服务器来启用gRPC-Web代理,以Envoy为例,参考以下配置:

    http_filters:
    ...
    - name: envoy.grpc_web
    
    1. 在gRPC-Web客户端中配置

    可以使用improbable-eng/grpc-web库来对gRPC-Web客户端进行配置。具体方法请参考:https://github.com/grpc/grpc-web#javascript-client

    下面是一个使用gRPC-Web的示例:

    服务端代码:

    from concurrent import futures
    import grpc
    import helloworld_pb2
    import helloworld_pb2_grpc
    
    class Greeter(helloworld_pb2_grpc.GreeterServicer):
    
        def SayHello(self, request, context):
            return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
    
        def SayHelloAgain(self, request, context):
            return helloworld_pb2.HelloReply(message='Hello again, %s!' % request.name)
    
    def serve():
        server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
        helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
        server.add_insecure_port('[::]:50051')
        server.start()
        server.wait_for_termination()
    
    if __name__ == '__main__':
        serve()
    

    客户端代码:

    <!DOCTYPE html>
    <html>
      <head>
        <title>gRPC-Web Example</title>
        <!-- Load gRPC-Web directly from the server -->
        <script src="https://unpkg.com/grpc-web/dist/grpc-web.js"></script>
        <!-- Load our generated code, under /proto/ -->
        <script src="./helloworld_pb.js"></script>
        <script src="./helloworld_grpc_web_pb.js"></script>
        <script>
          function run() {
            var request = new helloworld_pb.HelloRequest();
            request.setName(document.getElementById("name").value);
            var client = new helloworld_grpc_web.GreeterClient('http://localhost:8080');
            client.sayHello(request, {}, (err, response) => {
              document.getElementById("output").innerHTML = response.getMessage();
            });
          }
        </script>
      </head>
      <body>
        <input type="text" id="name"><button onclick="run()">send</button>
        <p id="output"></p>
      </body>
    </html>
    

    注意这里的客户端使用了gRPC-Web库,页面中也包含了相关的JavaScript脚本。在这种情况下,客户端会请求localhost:8080/grpc-web,Envoy会代理请求,将HTTP/1.1协议转换为gRPC-Web协议。

    参考资料:

    https://www.grpc.io/docs/platforms/web/basics/

    https://developers.google.com/web/showcase/2016/grpc
    如果我的回答解决了您的

    评论
  • aierda 2023-04-03 17:17
    关注

    gRPC-Webd确实可以解决这个问题,感谢大家的帮忙!

    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 4月11日
  • 已采纳回答 4月3日
  • 创建了问题 3月28日

悬赏问题

  • ¥20 C语言字符串不区分大小写字典排序相关问题
  • ¥15 关于#python#的问题:我希望通过逆向技术爬取1688搜索页下滑加载的数据
  • ¥15 学习C++过程中遇到的问题
  • ¥15 关于Linux的终端里,模拟实现一个带口令保护的屏保程序遇到的输入输出的问题!(语言-c语言)
  • ¥15 学习C++过程中遇到的问题
  • ¥15 请问,这个嵌入式Linux系统怎么分析,crc检验区域在哪
  • ¥15 二分类改为多分类问题
  • ¥15 Unity微信小游戏上调用ReadPixels()方法报错
  • ¥15 如何通过求后验分布求得样本中属于两种物种其中一种的概率?
  • ¥15 q从常量变成sin函数,怎么改写python代码?