negroni中间件中的请求上下文集在嵌套的gorilla子计算机中丢失
我的基本negroni中间件中的请求上下文集在嵌套的gorilla子计算机中丢失,go,gorilla,negroni,Go,Gorilla,Negroni,我的基本main设置: muxRouter := mux.NewRouter() v1Router.Router(muxRouter.PathPrefix("/v1").Subrouter()) http.Handle("/", muxRouter) n := negroni.Classic() n.Use(negroni.HandlerFunc(apiRouter.Middleware)) n.UseHandler(muxRouter) s := &http.Server{
main
设置:
muxRouter := mux.NewRouter()
v1Router.Router(muxRouter.PathPrefix("/v1").Subrouter())
http.Handle("/", muxRouter)
n := negroni.Classic()
n.Use(negroni.HandlerFunc(apiRouter.Middleware))
n.UseHandler(muxRouter)
s := &http.Server{
Addr: ":6060",
Handler: n,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
但是,在v1Router.Router中的某些handlerFunc中,当尝试获取上下文的值时,结果为零:
domain := context.Get(req, helperKeys.DomainName)
fmt.Println("DomainName", domain)
打印:DomainName
我知道Set
方法是正确的,因为在apiRouter中设置后立即获取值。中间件将返回正确的字符串值。我使用了Go 1.7
内置的上下文
:
context.Set(req, helperKeys.DomainName, "some-value")
// Replaced with:
ctx := req.Context()
ctx = context.WithValue(ctx, helperKeys.DomainName, "some-value")
req = req.WithContext(ctx)
及
根据您的回答,您似乎正在尝试在上下文中存储数据库。我不建议这样做。相反,请尝试以下方法:
type Something struct {
DB *sql.DB // or some other DB object
}
func (s *Something) CreateUser(w http.ResponseWriter, r *http.Request) {
// use s.DB to access the database
fmt.Fprintln(w, "Created a user...")
}
func main() {
db := ...
s := Something{db}
http.HandleFunc("/", s.CreateUser)
// ... everything else is pretty much like normal.
}
这样,处理程序就可以访问数据库,而不必每次都在上下文中设置它。上下文值应该为运行时之前无法设置的内容保留。例如,特定于该web请求的请求ID。超出请求期限的内容通常不属于此类别,并且您的DB连接将超过请求期限
如果确实需要上下文值,则应:
使用键入的getter和setter
“包应将键定义为未报告的类型,以避免冲突。”-
下面是一个示例,我将在中详细介绍上下文值:
请使用更长版本的类型转换(域,确定:=req.Context().Value(…)
如果出现诸如从未设置值之类的问题,这将为您节省很多麻烦。我还将使用自定义getter/setter来处理上下文值和未报告的键。所有这些在实践中都更安全,并且没有太多的代码。嘿,感谢您的提醒,但我实际上并没有存储数据库,我只是存储连接的副本我在main函数中连接到数据库,并且只在每个请求的上下文中存储会话的一个副本,这仍然是普遍不赞成的-DB连接的副本根本不是特定于请求的,并且可以通过我在这里展示的第一种方法轻松访问,从长远来看,这更安全。更符合犹太教义的可能是存储,比如说从DB连接创建的一个事务,该事务只会在请求存在的时候存在。也就是说,我希望这样做可以加快速度。我只是想让你知道,随着应用的发展,有更好的方法来处理这个问题,更易于维护和调试。
domain := context.Get(req, helperKeys.DomainName)
// Replaced with:
domain := req.Context().Value(helperKeys.DomainName).(string)
type Something struct {
DB *sql.DB // or some other DB object
}
func (s *Something) CreateUser(w http.ResponseWriter, r *http.Request) {
// use s.DB to access the database
fmt.Fprintln(w, "Created a user...")
}
func main() {
db := ...
s := Something{db}
http.HandleFunc("/", s.CreateUser)
// ... everything else is pretty much like normal.
}
type userCtxKeyType string
const userCtxKey userCtxKeyType = "user"
func WithUser(ctx context.Context, user *User) context.Context {
return context.WithValue(ctx, userCtxKey, user)
}
func GetUser(ctx context.Context) *User {
user, ok := ctx.Value(userCtxKey).(*User)
if !ok {
// Log this issue
return nil
}
return user
}