zoukankan      html  css  js  c++  java
  • api_response.go

    package http_api

    import (
        "encoding/json"
        "fmt"
        "io"
        "net/http"
        "time"

        "github.com/julienschmidt/httprouter"
        "github.com/nsqio/nsq/internal/app"
    )

    type Decorator func(APIHandler) APIHandler

    type 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)
        })
    }

  • 相关阅读:
    (11)模糊图片操作---均值模糊
    (10)绘制形状和文字
    (9)调整图像的亮度和对比度
    (8)图像混合
    (7)opencv图片内部的基本处理
    C#中的线程池使用(二)
    C#中的线程池使用(一)
    C#中线程的委托
    为PyCharm自动配置作者信息
    为PyCharm配置QT
  • 原文地址:https://www.cnblogs.com/zhangboyu/p/7457450.html
Copyright © 2011-2022 走看看