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
    }