mongo客户端在main函数中设置,其他模块函数接收nil值
Posted
技术标签:
【中文标题】mongo客户端在main函数中设置,其他模块函数接收nil值【英文标题】:Mongo client set in main function, functions in other modules receive nil value 【发布时间】:2021-06-05 19:59:10 【问题描述】:我有一个使用 mux 和 mongo-driver 的宁静 API。按照教程,我尝试在主包中设置服务器和 mongo 客户端:
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
c "github.com/moonlightfight/elo-backend/config"
"github.com/moonlightfight/elo-backend/routes/admin"
"github.com/moonlightfight/elo-backend/routes/tournament"
"github.com/spf13/viper"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var client *mongo.Client
func main()
// Set the file name of the configurations file
viper.SetConfigName("config")
// Set the path to look for the configurations file
viper.AddConfigPath(".")
// Enable VIPER to read Environment Variables
viper.AutomaticEnv()
viper.SetConfigType("yml")
var configuration c.Configurations
if err := viper.ReadInConfig(); err != nil
fmt.Printf("Error reading config file, %s", err)
err := viper.Unmarshal(&configuration)
if err != nil
fmt.Printf("Unable to decode into struct, %v", err)
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
clientOptions := options.Client().ApplyURI(fmt.Sprintf("mongodb+srv://%s:%s@cluster0.ucnph.mongodb.net/%s?retryWrites=true&w=majority", configuration.Database.DBUser, configuration.Database.DBPass, configuration.Database.DBName))
port := fmt.Sprintf(":%d", configuration.Server.Port)
mongo.Connect(ctx, clientOptions)
router := mux.NewRouter()
router.HandleFunc("/api/admin", admin.CreateAdminEndpoint).Methods("POST")
router.HandleFunc("/api/admin/login", admin.AdminLoginEndpoint).Methods("POST")
router.HandleFunc("/api/tournament/getfromweb", tournament.GetTournamentData).Methods("GET")
fmt.Printf("server listening on http://localhost%v", port)
http.ListenAndServe(port, router)
现在,为了更简洁地管理我的代码,我设置了模块(正如您在 main 上的导入中看到的那样)来处理 mux 将用于端点的函数。
在一种特定情况下(处理“/api/admin”端点:
package admin
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
"github.com/dgrijalva/jwt-go"
c "github.com/moonlightfight/elo-backend/config"
m "github.com/moonlightfight/elo-backend/models"
"github.com/spf13/viper"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/crypto/bcrypt"
)
var client *mongo.Client
// other code here
func CreateAdminEndpoint(response http.ResponseWriter, request *http.Request)
response.Header().Set("content-type", "application/json")
var admin m.Admin
err := json.NewDecoder(request.Body).Decode(&admin)
if err != nil
log.Println(err)
// encrypt user password
admin.Password = HashPassword(admin.Password)
fmt.Println(client)
collection := client.Database("test").Collection("Admin")
ctx, ctxErr := context.WithTimeout(context.Background(), 5*time.Second)
if ctxErr != nil
log.Println(ctxErr)
result, resErr := collection.InsertOne(ctx, admin)
if resErr != nil
log.Println(resErr)
json.NewEncoder(response).Encode(result)
运行时,我收到以下错误:
2021/06/05 02:02:39 http: panic serving [::1]:53359: runtime error: invalid memory address or nil pointer dereference
这指向我在端点函数中定义集合的行,它记录为具有 nil 值。我显然没有在模块中正确定义 mongo 客户端,并且不确定跨多个模块维护此客户端连接的最佳实践。
【问题讨论】:
一个模块不是一个包,也没有什么魔法:如果你想初始化一个包级变量,你必须导出它并初始化它(例如从 main)。 在这种情况下最好的方法是什么? @lanierc 在主包中,导入管理包创建客户端并分配给管理包变量。导出 admin 客户端变量,以便 main 可以访问它:admin.Client = client
。
【参考方案1】:
在避免全局变量的同时执行此操作的标准方法是定义一个代表您的服务器的struct
,其方法将是处理程序。然后这些方法共享结构的数据,然后您将诸如 mongo 客户端之类的东西放在那里。
类似这样的东西(在您的admin
包中):
type Server struct
client *mongo.Client
func NewServer(client *mongo.Client) *Server
return &Serverclient: client
func (srv *Server) CreateAdminEndpoint(response http.ResponseWriter, request *http.Request)
// ...
// use srv.client here
//
现在在main
中,您可以这样创建服务器:
client, err := mongo.Connect(...)
// handle err!
srv := admin.NewServer(client)
router := mux.NewRouter()
router.HandleFunc("/api/admin", srv.CreateAdminEndpoint).Methods("POST")
【讨论】:
以上是关于mongo客户端在main函数中设置,其他模块函数接收nil值的主要内容,如果未能解决你的问题,请参考以下文章