装饰器模式在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
    }
}

 

posted @ 2018-03-26 14:29  TylerJin  阅读(260)  评论(0)    收藏  举报