如何使用 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)
}
我正在做一个 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)
}