使用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

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

基于最新版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项目之间的双向通信。如果您有其他问题或需要更多帮助,请随时提问。

该回答引用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。

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>();
        });
    }
}

以下答案由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
如果我的回答解决了您的

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