Go Gorilla恐慌处理程序以自定义状态响应

时间:2015-11-24 21:48:17

标签: go gorilla

在大猩猩中,使用RecoveryHandler我们可以抑制恐慌。但是有一个处理程序或库方法来响应特定的Http状态代码和给定错误类型的消息 例如,如果发生Mandatory field missing error恐慌,可能需要回复Http 400以及有效负载确切错误的有意义消息。

建议的方法是什么?
更新 在代码中:列出了2种方法

  1. 处理每次方法调用时返回的错误并构建响应。
  2. 不使用返回错误,而是使用自定义错误类型发生混乱,并将错误恢复推迟到func以构建响应。这使代码易于阅读,重复性更低。
  3. func fooHandler(w http.ResponseWriter, r *http.Request) {
        //decode the request body into a struct instance
        if err := decode(r, myInstance); err != nil {
            sendErrorResponse(w,err,http.StatusBadRequest)
            return
        }
        //validate the struct instance for all mandatory keys presence
        if err := file.validate(); err != nil {
            sendErrorResponse(w,err,http.StatusBadRequest)
            return
        }
        //call DB and validate the response and handle the error
    
        //do some computation and again handle error.
    
        //finally construct response 
    }
    
    func barHandler(w http.ResponseWriter, r *http.Request) {
        //similar to above handler many funcs are called before the response is contruscted
    }
    
    func tomHandler(w http.ResponseWriter, r *http.Request) {
        //similar to above handler many funcs are called before the response is contruscted
    }
    
    func differentHandler(w http.ResponseWriter, r *http.Request) {
        defer recoverForErrors(w,r)
        // call as many funcs as you need.
        // validation, decoding etc will panic instead of returning errors.
        // This will avoid the repetitive boiler plate code of handling error and converting to meaningful error response
        // instead all this logic is pushed to recoverForErrors func. Which retrieves the error from panic and checks for 
        // specific error type to construct the error http response
    }
    

1 个答案:

答案 0 :(得分:4)

尽可能依靠标准库提供的接口是惯用的。在这种情况下,来自net/http包的http.Handler接口。

在您的情况下,您可以创建一个新类型,允许处理程序返回错误类型,并集中处理所有这些错误情况。

// StatusError wraps an existing error with a HTTP status code.
type StatusError struct {
    Status int
    // Allows you to wrap another error
    Err error
}

func (e *StatusError) Error() string {
    return e.Error()
}

type AppHandler func(w http.ResponseWriter, r *http.Request) error

// Satisfies the http.Handler interface
func (ah AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Centralises your error handling
    err := ah(w, r)
    if err != nil {
        switch e := a.(type) {
        case *StatusError:
            switch e.Status {
            case 400:
                http.Error(w, e.Err.Error(), 400)
                return
            case 404:
                http.NotFound(w, r)
                return
            default:
                http.Error(w, http.StatusText(500), 500)
                return
        }
        default:
            http.Error(w, http.StatusText(500), 500)
            return
        }
}

// Your handlers will look like this
func SomeHandler(w http.ResponseWriter, r *http.Request) error {
    err := decode(r, myInstance)
    if err != nil {
        return &StatusError{400, err}
    }

    err := file.validate()
    if err != nil {
        return &StatusError{400, err}
    }

    // Continue on...
    return nil
}

您在这里获得的好处包括:

  • 对于可以处理的错误没有恐慌
  • 您可以在ServeHTTP方法中集中处理错误 - 例如,对于400错误,您可以将错误原因写入响应。对于500个错误,您可能会返回一般消息,因为HTTP 500不是用户可以解决的问题。
  • 您的处理函数显式返回错误,您不再需要记住使用裸return语句来避免继续执行。
  • 您的StatusError类型使用状态代码包装错误,但仍允许您轻松检查/记录/写出包装错误。

进一步阅读: