我刚读了
this blog post关于创建函数类型并在该函数上实现.ServeHTTP()方法以便能够处理错误.例如:
type appError struct { Error error Message string Code int } type appHandler func(http.ResponseWriter,*http.Request) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) { if e := fn(w,r); e != nil { // e is *appError,not os.Error. http.Error(w,e.Message,e.Code) } } func init() { http.Handle("/view",appHandler(viewRecord)) //viewRecord is an appHandler function }
我喜欢这种方法,但我无法在概念上弄清楚如何通过处理程序层包含上下文对象.例如:
func init() { http.Handle("/view",AuthHandler(appHandler(viewRecord))) }
AuthHandler可能会创建一个& SessionToken {User:user}对象,并在每个请求的context.Context对象中设置该对象.我无法弄清楚如何将它传递给viewRecord处理程序.想法?
我可以想到几种方法来做到这一点.
原文链接:https://www.f2er.com/go/186819.html传递上下文
首先,您可以更改签名以接受上下文
type appHandler func(http.ResponseWriter,*http.Request,context.Context) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) { if e := fn(w,r,nil); e != nil { // e is *appError,not os.Error. http.Error(w,e.Code) } }
现在我假设AuthHandler与身份验证有关,并在上下文对象中设置用户.
你可以做的是创建另一个设置上下文的类型处理程序.像这样
type authHandler func(http.ResponseWriter,context.Context) *appError func (fn authHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) { // setup authentication here uid := 1 // setup the context the way you want parent := context.TODO() ctx := context.WithValue(parent,userIdKey,uid) if e := fn(w,ctx); e != nil { // e is *appError,not os.Error. http.Error(w,e.Code) } }
这样您就可以通过以下方式使用它
func init() { http.Handle("/view",appHandler(viewRecord)) // don't require authentication http.Handle("/viewAuth",authHandler(viewRecord)) // require authentication }
这是完整的代码
package main import ( "fmt" "net/http" "code.google.com/p/go.net/context" ) type appError struct { Error error Message string Code int } type key int const userIdKey key = 0 type appHandler func(http.ResponseWriter,e.Code) } } type authHandler func(http.ResponseWriter,r *http.Request) { // setup authentication here uid := 1 // setup the context the way you want parent := context.TODO() ctx := context.WithValue(parent,uid) if e := fn(w,e.Code) } } func viewRecord(w http.ResponseWriter,r *http.Request,c context.Context) *appError { if c == nil { fmt.Fprintf(w,"User are not logged in") } else { uid := c.Value(userIdKey) fmt.Fprintf(w,"User logged in with uid: %d",uid) } return nil } func init() { http.Handle("/view",appHandler(viewRecord)) // viewRecord is an appHandler function http.Handle("/viewAuth",authHandler(viewRecord)) // viewRecord is an authHandler function } func main() { http.ListenAndServe(":8080",nil) }
创建地图上下文
您可以创建,而不是传递上下文
var contexts map[*http.Request]context.Context
并使用上下文[r]获取上下文.
但由于map不是线程安全的,因此必须使用互斥锁保护对映射的访问.
猜猜看,这是大猩猩的背景为你做的,我认为这是更好的方法
https://github.com/gorilla/context/blob/master/context.go#l20-28
这是完整的代码
package main import ( "fmt" "net/http" "github.com/gorilla/context" ) type appError struct { Error error Message string Code int } type key int const userIdKey key = 0 type appHandler func(http.ResponseWriter,*http.Request) *appError func (fn authHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) { // setup authentication here uid := 1 context.Set(r,r *http.Request) *appError { if uid,ok := context.GetOk(r,userIdKey); !ok { fmt.Fprintf(w,"User are not logged in") } else { fmt.Fprintf(w,appHandler(viewRecord)) // don't require authentication http.Handle("/viewAuth",authHandler(viewRecord)) // require authentication } func main() { http.ListenAndServe(":8080",nil) }
func AuthHandler(h appHandler) appHandler { return func(w http.ResponseWriter,r *http.Request) *appError { // setup authentication here uid := 1 context.Set(r,uid) return h(w,r) } } func init() { http.Handle("/view",appHandler(viewRecord)) // don't require authentication http.Handle("/viewAuth",appHandler(AuthHandler(viewRecord))) // require authentication }