【问题标题】:How can I serve files while using GRPC如何在使用 GRPC 时提供文件
【发布时间】:2019-10-27 04:21:14
【问题描述】:

有什么方法可以使用 GRPC 在 Go 中提供文件,例如 gin-gonic's variant

router.Static("/static", "/var/www")

【问题讨论】:

标签: go grpc


【解决方案1】:

你不能完全那样做。
但是您可以使用 proto bytes 类型并将文件字节放在该字段中。

另外(如 cmets 中所指出的)对于大文件,您应该使用流式传输而不是一元调用。 (大多数 GRPC 实现对每条消息的限制为 4MB)。

原型示例:

syntax = "proto3";

message Response {
    bytes fileChunk = 1;
}
message Request {
    string fileName = 1;
}

service TestService {
    rpc Download(Request) returns (stream Response);
}

服务器实现示例:

func (srv *Server) Download(req *pbgo.Request, responseStream pbgo.TestService_DownloadServer) error {
    bufferSize := 64 *1024 //64KiB, tweak this as desired
    file, err := os.Open(req.GetFileName())
    if err != nil {
        fmt.Println(err)
        return err
    }
    defer file.Close()
    buff := make([]byte, bufferSize)
    for {
        bytesRead, err := file.Read(buff)
        if err != nil {
            if err != io.EOF {
                fmt.Println(err)
            }
            break
        }
        resp := &pbgo.Response{
            FileChunk: buff[:bytesRead],
        }
        err = responseStream.Send(resp)
        if err != nil {
            log.Println("error while sending chunk:", err)
            return err
        }
    }
    return nil
}

客户会这样称呼它:

conn, err := grpc.Dial("localhost:9090", grpc.WithInsecure())
if err != nil {
    log.Fatal("client could connect to grpc service:", err)
}
c := pbgo.NewTestServiceClient(conn)
fileStreamResponse, err := c.Download(context.TODO(), &pbgo.Request{
    FileName: "test.txt",
})
if err != nil {
    log.Println("error downloading:", err)
    return
}
for {
    chunkResponse, err := fileStreamResponse.Recv()
    if err == io.EOF {
        log.Println("received all chunks")
        break
    }
    if err != nil {
        log.Println("err receiving chunk:", err)
        break
    }
    log.Printf("got new chunk with data: %s \n", chunkResponse.FileChunk)
}

如果您需要能够提供任意文件,则需要处理允许提供的文件(比如有人请求文件 /etc/passwd 或其他文件)。
不确定这里的用例到底是什么。

【讨论】:

  • gRPC 消息有默认大小限制(4MB?)。因此,如果没有分块,任何大文件都无法像这样提供。
  • 没意识到,谢谢。所以那时需要一个流式 rpc 调用。我会尝试并更新帖子。
  • 是的,在这种情况下,我流式传输 gRPC 将是理想的选择。每条消息都可以保存块信息,例如“chunk 3 of 8”和字节范围,因此客户端可以准备如何接收文件,例如搜索写入等。
  • @erikbozic 如果是 react-js 并且在服务器端对 grpc 端点使用 http 映射/注释,如何处理客户端?
猜你喜欢
  • 2011-01-08
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 2013-03-06
  • 2020-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多