【问题标题】:How to serve a file from mongodb with golang如何使用 golang 从 mongodb 提供文件
【发布时间】:2018-11-14 20:48:53
【问题描述】:

我正在做一个 go 项目,我需要提供存储在 mongodb 中的文件。这些文件存储在 GridFs 中。我使用 gopkg.in/mgo.v2 作为包来连接和查询数据库。

我可以从数据库中检索文件,这并不难。

f, err := s.files.OpenId(id)

但我怎样才能使用 http 提供该文件? 我使用 JulienSchmidt 路由器来处理所有其他的 restfull 请求。 我找到的解决方案总是使用静态文件,而不是来自数据库的文件。

提前致谢

【问题讨论】:

  • 为什么会有所不同? GridFS 实现都使输出“看起来像一个文件”。所以它和读取任何文件句柄并返回内容是一样的。

标签: mongodb go gridfs fileserver


【解决方案1】:

提示:建议使用github.com/globalsign/mgo 而不是gopkg.in/mgo.v2(后者不再维护)。


mgo.GridFile 类型实现了io.Reader,因此您可以使用io.Copy() 将其内容复制到http.ResponseWriter

但由于mgo.GridFile 也实现了io.Seeker,您可以利用http.ServeContent()。引用其文档:

ServeContent 优于 io.Copy 的主要优点是它可以正确处理 Range 请求、设置 MIME 类型以及处理 If-Match、If-Unmodified-Since、If-None-Match、If-Modified-Since 和If-Range 请求。

提供文件的示例处理程序:

func serveFromDB(w http.ResponseWriter, r *http.Request) {
    var gridfs *mgo.GridFS // Obtain GridFS via Database.GridFS(prefix)

    name := "somefile.pdf"
    f, err := gridfs.Open(name)
    if err != nil {
        log.Printf("Failed to open %s: %v", name, err)
        http.Error(w, "something went wrong", http.StatusInternalServerError)
        return
    }
    defer f.Close()

    http.ServeContent(w, r, name, time.Now(), f) // Use proper last mod time
}

【讨论】:

  • 我正在考虑这个问题,但希望有另一种解决方案可以直接提供文件...
  • @WimVanLaer 打开GridFile 后,只有一行:http.ServeContent()。你想要什么更简单的?显然,如何打开源是特定于源的。如果您需要在多个地方使用它,您可以创建一个实用函数,只需将wrname 参数传递给它。
  • 哦,我忘了 GridFile 实现了搜索文件,误读了那部分......我的错
【解决方案2】:

它很旧,但我通过导入获得了 goMongo 驱动程序的另一个解决方案
"go.mongodb.org/mongo-driver/mongo/gridfs"

var bucket *gridfs.Bucket //creates a bucket
dbConnection, err := db.GetDBCollection() //connect db with your your
if err != nil {
    log.Fatal(err)
}
bucket, err = gridfs.NewBucket(dbConnection)
if err != nil {
    log.Fatal(err)
}
name := "br100_update.txt"
downloadStream, err := bucket.OpenDownloadStreamByName(name)
if err != nil {
    log.Printf("Failed to open %s: %v", name, err)
    http.Error(w, "something went wrong", http.StatusInternalServerError)
    return
}
defer func() {
    if err := downloadStream.Close(); err != nil {
        log.Fatal(err)
    }
}()

// Use SetReadDeadline to force a timeout if the download does not succeed in 
// 2 seconds.
 if err = downloadStream.SetReadDeadline(time.Now().Add(2 * time.Second)); err 
  != nil {
  log.Fatal(err)
 }

//下面这段代码用来读取文件

 fileBuffer := bytes.NewBuffer(nil)
 if _, err := io.Copy(fileBuffer, downloadStream); err != nil {
  log.Fatal(err)

}

【讨论】:

    猜你喜欢
    • 2019-01-09
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2021-09-30
    • 2018-02-07
    • 2019-02-10
    • 2021-09-20
    • 1970-01-01
    相关资源
    最近更新 更多