使用GRPC时如何提供文件 [英] How can I serve files while using GRPC

查看:220
本文介绍了使用GRPC时如何提供文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以在GRPC中使用Go服务文件,例如 gin-gonic的变体 gin-gonic的变体:

Is there any way how to serve files in Go with GRPC, like in gin-gonic's variant:

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

推荐答案

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

You can't do it exactly like that.
But you can use the proto bytes type and put the file bytes in that field.

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

Also (as pointed out in the comments) with large files you should use streaming instead of a unary call. (most GRPC implementation have a limit of 4MB per message).

原始示例:

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或其他内容).
不知道这里的用例是什么.

If you need to be able to serve arbitrary files, you would need to handle which files you allow serving (say someone requests the file /etc/passwd or something).
Not sure what exactly is the use case here.

这篇关于使用GRPC时如何提供文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆