装饰器模式在nsq中的运用
nsq使用装饰器模式封装http的请求响应,通过实现不同的装饰器来实现不同的功能
APIHandler用于处理http请求与响应,Decorator接收原始的handler,经过处理后返回新的handler
type Decorator func(APIHandler) APIHandler type APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)
迭代器方法通过传入原始的handler以及迭代器组,实现相应迭代器的功能
func Decorate(f APIHandler, ds ...Decorator) httprouter.Handle { decorated := f for _, decorate := range ds { decorated = decorate(decorated) } return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { decorated(w, req, ps) } }
以ping请求举例,nsq在处理ping请求时提供了基础的pingHandler,然后提供了日志记录以及将响应写入客户端的装饰器
router.Handle("GET", "/ping", http_api.Decorate(s.pingHandler, log, http_api.PlainText))
pingHandler单纯的返回OK至客户端
func (s *httpServer) pingHandler(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { return "OK", nil }
log Decorator记录请求的耗时,状态,方法,URL以及IP等信息
func Log(logf lg.AppLogFunc) Decorator { return func(f APIHandler) APIHandler { return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { start := time.Now() response, err := f(w, req, ps) elapsed := time.Since(start) status := 200 if e, ok := err.(Err); ok { status = e.Code } logf(lg.INFO, "%d %s %s (%s) %s", status, req.Method, req.URL.RequestURI(), req.RemoteAddr, elapsed) return response, err } } }
plainText Decorator将handler返回的数据写入response中
func PlainText(f APIHandler) APIHandler { return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { code := 200 data, err := f(w, req, ps) if err != nil { code = err.(Err).Code data = err.Error() } switch d := data.(type) { case string: w.WriteHeader(code) io.WriteString(w, d) case []byte: w.WriteHeader(code) w.Write(d) default: panic(fmt.Sprintf("unknown response type %T", data)) } return nil, nil } }

浙公网安备 33010602011771号