[英]How do I stream with grpc-web and use a REST API on the same port?
I have a server witten in Go that uses cmux
to allow multiple protocols to run on the same port, but there's a limitation specified in the README saying that我在 Go 中有一个服务器,它使用cmux
来允许多个协议在同一个端口上运行,但是 README 中指定了一个限制说
cmux
matches the connection when it's accepted.cmux
在连接被接受时匹配它。 For example, one connection can be either gRPC or REST, but not both.例如,一个连接可以是 gRPC 或 REST,但不能同时是两者。 That is, we assume that a client connection is either used for gRPC or REST.也就是说,我们假设客户端连接用于 gRPC 或 REST。
I need the browser to be able to both stream from grpc-web and call a REST API on the same port, but the browser reuses the same connection and causes the muxing to not work.我需要浏览器能够同时从 grpc-web 访问 stream 并调用 REST API 在同一个端口上,但浏览器重用相同的连接并导致复用不工作。
This is a pretty tricky problem to identify.这是一个非常棘手的问题。 Since browsers prefer to use an existing TCP connection for pipelining, the mux tends to send packets to the wrong protocol handler, for example it could send grpc-web
packets to REST, and vice versa.由于浏览器更喜欢使用现有的 TCP 连接进行流水线操作,因此多路复用器倾向于将数据包发送到错误的协议处理程序,例如它可以将grpc-web
数据包发送到 REST,反之亦然。 Luckily, there is a pretty simple solution for this:幸运的是,有一个非常简单的解决方案:
package main
listener := net.Listen("tcp", ":2289")
multiplexer := cmux.New(listener)
grpcListener := multiplexer.Match(cmux.HTTP2())
httpListener := multiplexer.Match(cmux.HTTP1Fast())
grpcServer := grpc.Server()
wrappedGrpc := grpcweb.WrapServer(grpcServer)
go func() {
httpServer := echo.New()
(&http.Server{
Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
if strings.Contains(req.Header.Get("Access-Control-Request-Headers"), "x-grpc-web") || req.Header.Get("x-grpc-web") == "1" || req.Header.Get("Sec-Websocket-Protocol") == "grpc-websockets" {
inst.API.GrpcWebServer.ServeHTTP(resp, req)
} else {
httpServer.ServeHTTP(resp, req)
}
}),
}).Serve(httpListener)
}()
go func() {
grpcServer.Serve(grpcListener)
}()
go func() {
multiplexer.Serve()
}()
How does this work?这是如何运作的?
Essentially, instead of using cmux
's default muxing (which only muxes per-connection) we registered a new mini http server handler on all HTTP requests coming in, which then lets us explicitly check headers and call handlers directly.本质上,我们没有使用cmux
的默认多路复用(仅对每个连接进行多路复用),而是在所有传入的 HTTP 请求上注册了一个新的迷你 http 服务器处理程序,然后我们可以显式检查标头并直接调用处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.