我刚读了
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处理程序.想法?
我可以想到几种方法来做到这一点.
传递上下文
首先,您可以更改签名以接受上下文
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
}

