api_response.go
2021-09-06 12:11
标签:int header .com utf-8 his handle backward data mars package http_apiimport ( "encoding/json" "fmt" "io" "net/http" "time" "github.com/julienschmidt/httprouter" "github.com/nsqio/nsq/internal/app")type Decorator func(APIHandler) APIHandlertype APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)type Err struct { Code int Text string}func (e Err) Error() string { return e.Text}func acceptVersion(req *http.Request) int { if req.Header.Get("accept") == "application/vnd.nsq; version=1.0" { return 1 } return 0}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 }}func NegotiateVersion(f APIHandler) APIHandler { return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { data, err := f(w, req, ps) if err != nil { if acceptVersion(req) == 1 { RespondV1(w, err.(Err).Code, err) } else { // this handler always returns 500 for backwards compatibility Respond(w, 500, err.Error(), nil) } return nil, nil } if acceptVersion(req) == 1 { RespondV1(w, 200, data) } else { Respond(w, 200, "OK", data) } return nil, nil }}func V1(f APIHandler) APIHandler { return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { data, err := f(w, req, ps) if err != nil { RespondV1(w, err.(Err).Code, err) return nil, nil } RespondV1(w, 200, data) return nil, nil }}func Respond(w http.ResponseWriter, statusCode int, statusTxt string, data interface{}) { var response []byte var err error switch data.(type) { case string: response = []byte(data.(string)) case []byte: response = data.([]byte) default: w.Header().Set("Content-Type", "application/json; charset=utf-8") response, err = json.Marshal(struct { StatusCode int `json:"status_code"` StatusTxt string `json:"status_txt"` Data interface{} `json:"data"` }{ statusCode, statusTxt, data, }) if err != nil { response = []byte(fmt.Sprintf(`{"status_code":500, "status_txt":"%s", "data":null}`, err)) } } w.WriteHeader(statusCode) w.Write(response)}func RespondV1(w http.ResponseWriter, code int, data interface{}) { var response []byte var err error var isJSON bool if code == 200 { switch data.(type) { case string: response = []byte(data.(string)) case []byte: response = data.([]byte) case nil: response = []byte{} default: isJSON = true response, err = json.Marshal(data) if err != nil { code = 500 data = err } } } if code != 200 { isJSON = true response = []byte(fmt.Sprintf(`{"message":"%s"}`, data)) } if isJSON { w.Header().Set("Content-Type", "application/json; charset=utf-8") } w.Header().Set("X-NSQ-Content-Type", "nsq; version=1.0") w.WriteHeader(code) w.Write(response)}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) }}func Log(l app.Logger) 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 } l.Output(2, fmt.Sprintf("%d %s %s (%s) %s", status, req.Method, req.URL.RequestURI(), req.RemoteAddr, elapsed)) return response, err } }}func LogPanicHandler(l app.Logger) func(w http.ResponseWriter, req *http.Request, p interface{}) { return func(w http.ResponseWriter, req *http.Request, p interface{}) { l.Output(2, fmt.Sprintf("ERROR: panic in HTTP handler - %s", p)) Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { return nil, Err{500, "INTERNAL_ERROR"} }, Log(l), V1)(w, req, nil) }}func LogNotFoundHandler(l app.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { return nil, Err{404, "NOT_FOUND"} }, Log(l), V1)(w, req, nil) })}func LogMethodNotAllowedHandler(l app.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { return nil, Err{405, "METHOD_NOT_ALLOWED"} }, Log(l), V1)(w, req, nil) })}api_response.go标签:int header .com utf-8 his handle backward data mars 原文地址:http://www.cnblogs.com/zhangboyu/p/7457450.html