如何使用 golang 从 mongodb 提供文件

How to serve a file from mongodb with golang

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

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

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

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

提前致谢

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


mgo.GridFile type implements io.Reader, so you could use io.Copy() to copy its content into the http.ResponseWriter.

但由于 mgo.GridFile 也实现了 io.Seeker, you may take advantage of http.ServeContent()。引用其文档:

The main benefit of ServeContent over io.Copy is that it handles Range requests properly, sets the MIME type, and handles If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since, and If-Range requests.

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

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
}

它很旧,但我通过导入
得到了 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)

}