dtgu21994537 2015-11-24 21:48
浏览 22

去大猩猩恐慌处理程序以自定义状态进行响应

In Gorilla, using RecoveryHandler we could suppress the panics. However is there a handler or a library method to respond with a specific Http status code and message for given error type.
For example, in case of a Panic for Mandatory field missing error, one would want to respond with Http 400 and a meaningful message of what exactly is wrong with the payload.

What is the recommended approach to do this?
UPDATE In code: 2 approaches are listed

  1. Handle errors returned at each method call and build the response.
  2. Instead of returning errors, panic with custom error types and defer the error recovery to a func to build the response. This makes the code easy to read and less repetitive.
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条回答 默认 最新

  • dongzhankou2090 2015-11-26 00:54
    关注

    It is idiomatic to lean on the interfaces provided by the standard library as much as possible. In this case, the http.Handler interface from the net/http package.

    In your case, you can create a new type that allows your handlers to return an error type, and handle all of those error cases centrally.

    // 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
    }
    

    The benefits you get here include:

    • No panicking for errors that can be handled
    • You can centralise your error handling in your ServeHTTP method - i.e. for 400 errors, you might write the error reason to the response. For 500 errors, you might return a generic message since a HTTP 500 isn't something the user can be expected to solve.
    • Your handler functions return errors explicitly, and you no longer need to remember to use naked return statements to avoid continued execution.
    • Your StatusError type wraps the error with a status code, but still allows you to inspect/log/write out the wrapped error easily.

    Further reading:

    评论

报告相同问题?

悬赏问题

  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示