在嵌套的大猩猩Subrouter中丢失了在negroni中间件中设置的请求上下文

时间:2017-02-14 15:09:22

标签: 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{
    Addr:           ":6060",
    Handler:        n,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())

apiRouter.Middleware内,我设置了以下内容:

context.Set(req, helperKeys.DomainName, "some-value")

但是,在尝试v1Router.Router上下文值时Get内的某些handlerFunc中,结果为nil:

domain := context.Get(req, helperKeys.DomainName)
fmt.Println("DomainName", domain)

打印:DomainName <nil>

我知道Set方法是正确的,因为在apiRouter.Middleware中设置值后立即获取值将返回正确的字符串值。

2 个答案:

答案 0 :(得分:1)

我最终使用Go 1.7内置的Context

context.Set(req, helperKeys.DomainName, "some-value")

// Replaced with:

ctx := req.Context()
ctx = context.WithValue(ctx, helperKeys.DomainName, "some-value")
req = req.WithContext(ctx)

domain := context.Get(req, helperKeys.DomainName)

// Replaced with:

domain := req.Context().Value(helperKeys.DomainName).(string)

答案 1 :(得分:0)

根据您的回答,您似乎正在尝试在上下文中存储数据库。我不建议那样做。而是尝试这样的事情:

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。比请求更长的事情通常不属于此类别,并且您的数据库连接将比请求更长。

如果确实需要上下文值,则应该:

  1. 使用键入的getter和setter
  2. “软件包应将密钥定义为未导出的类型以避免冲突。” - From the Go source code
  3. 下面显示了一个示例,我在this blog post中更多地讨论了上下文值:

    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
    }