我一直在使用mgo作为我的API,但我在MongoDB中看到了许多当前连接(同时使用少于5个设备进行测试)。通过db.serverStatus().connections在Mongo服务器上执行,我得到:{ "current" : 641, "available" : 838219, "totalCreated" : 1136 }。在下面,我将我的问题记录在mgo的Github中(问题#429):
db.serverStatus().connections
{ "current" : 641, "available" : 838219, "totalCreated" : 1136 }
我在Web服务器中使用mgo的方式是否正确?如果没有,您能举一个完整的例子吗?
此代码不起作用,将其视为几乎伪代码(由于缺少诸如导入的部分或配置来自何处和模型),但这正是我使用mgo的方式。
我必须澄清,我正在构建一个供多个移动设备和Web应用程序使用的API。
main.go
func main() { mongoDBDialInfo := &mgo.DialInfo{ Addrs: []string{config.DatabaseURL}, Timeout: 60 * time.Second, Database: config.DatabaseName, Username: config.DatabaseUsername, Password: config.DatabasePassword, } db, err := mgo.DialWithInfo(mongoDBDialInfo) if err != nil { log.Fatal("Cannot Dial Mongo: ", err) } defer db.Close() db.SetMode(mgo.Monotonic, true) phoneIndex := mgo.Index{ Key: []string{"pp"}, Unique: true, DropDups: true, Background: true, Sparse: true, } err = db.DB(config.DatabaseName).C("users").EnsureIndex(phoneIndex) if err != nil { panic(err) } router := mux.NewRouter() router.HandleFunc("/login", publicWithDB(login, db)).Methods("POST") if err := http.ListenAndServe(":5000", router); err != nil { log.Fatal(err) } } func publicWithDB(fn http.HandlerFunc, db *mgo.Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { dbsession := db.Copy() defer dbsession.Close() fn(w, r.WithContext(context.WithValue(r.Context(), contextKeyDatabase, dbsession))) } } func login(w http.ResponseWriter, r *http.Request) { r.ParseForm() // Parses the request body device := r.Form.Get("device") var deviceid bson.ObjectId if bson.IsObjectIdHex(device) { deviceid = bson.ObjectIdHex(device) } db := r.Context().Value(contextKeyDatabase).(*mgo.Session) var device models.Device err := db.DB(config.DatabaseName).C("devices").FindId(deviceid).One(&device) w.WriteHeader(200) w.Write([]byte(utils.ResponseToString(models.Response{Status: 200, Message: "asdasd", Data: device}))) }
我发布此消息是因为找不到完整的实现。
这是我如何看待自己和其他人在Go中构建Web应用程序的示例。此代码未经测试,仅作为示例。它缺少导入,并且可能有错误。
编辑 添加了一个中间件示例。
package main func main() { mongoDBDialInfo := &mgo.DialInfo{ Addrs: []string{config.DatabaseURL}, Timeout: 60 * time.Second, Database: config.DatabaseName, Username: config.DatabaseUsername, Password: config.DatabasePassword, } db, err := mgo.DialWithInfo(mongoDBDialInfo) if err != nil { log.Fatal("Cannot Dial Mongo: ", err) } defer db.Close() db.SetMode(mgo.Monotonic, true) phoneIndex := mgo.Index{ Key: []string{"pp"}, Unique: true, DropDups: true, Background: true, Sparse: true, } err = db.DB(config.DatabaseName).C("users").EnsureIndex(phoneIndex) if err != nil { panic(err) } mgoAdapter := mongo.NewAdapter(db, config.DatabaseName) deviceStore := mongo.NewDeviceStore(mgoAdapter) userStore := mongo.NewUserStore(mgoAdapter) loginController := controllers.NewLoginController(deviceStore) router := mux.NewRouter() router.HandleFunc("/login", middleware.AuthorizeUser(userStore)(http.HandlerFunc(loginController.Login)).Methods("POST") if err := http.ListenAndServe(":5000", router); err != nil { log.Fatal(err) } }
控制器/login.go
package controllers type LoginController struct { store DeviceStore } func NewLoginController(store stores.DeviceStore) *LoginController { return &LoginController{ store: store, } } func (c *LoginController) Login(w http.ResponseWriter, r *http.Request) { r.ParseForm() // Parses the request body device := r.Form.Get("device") data, err := c.store.FindByDevice(device) var respose models.Response if err != nil { w.WriteHeader(500) response = models.Response{Status: 500, Message: fmt.Sprintf("error: %s", err)} } else if data == nil { w.WriteHeader(404) response = models.Response{Status: 404, Message: "device not found"} } else { response = models.Response{Status: 200, Message: "device found", Data: data} } // Write sets header to 200 if it hasn't been set already w.Write([]byte(utils.ResponseToString(response))) }
store / stores.go
package stores type DeviceStore interface { FindByDevice(device string) (*models.Device, error) } type UserStore interface { FindByToken(token string) (*models.User, error) }
中间件/auth.go
package middleware func AuthorizeUser(store stores.UserStore) func(h *http.Handler) http.Handler { return func(h *http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Logic for authorizing user // Could also store user in the request context }) } }
mongo / mongo.go
package mongo type Adapter struct { session *mgo.Session databaseName string } func NewAdapter(session *mgo.Session, dbName string) *Adapter { return &Adapter{session: session, databaseName: dbName} } type deviceStore struct { *Adapter } func NewDeviceStore(adapter *Adapter) stores.DeviceStore { return &deviceStore{adapter} } const devices = "devices" func (s *deviceStore) FindByDevice(d string) (*models.Device, err) { sess := s.session.copy() defer sess.close() var deviceID bson.ObjectId if bson.IsObjectIdHex(d) { deviceID = bson.ObjectIdHex(d) } var device models.Device err := db.DB(s.databaseName).C(devices).FindId(deviceID).One(&device) if err == mgo.ErrNotFound { return nil, nil } return &device, err } type userStore struct { *Adapter } const users = "users" func NewUserStore(adapter *Adapter) stores.UserStore { return &userStore{adapter} } func (s *userStore) GetUserByToken(token string) (*models.User, error) { sess := s.session.copy() defer sess.close() var user models.User err := db.DB(s.databaseName).C(users).Find(bson.M{"token": token}).One(&user) if err == mgo.ErrNotFound { return nil, nil } return &user, err }