简体   繁体   中英

Terminate http request via header error code return or JSON response

How can I call multiple error return functions from a Handlefunc?

I have found something similar to what I need in this link: Golang: terminating or aborting an HTTP request .

So, in some cases, I need to return error response with HTTP error code, like below (code taken from link above):

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   // examine incoming params
   if !ok {
   http.Error(w, `Invalid input params!`, http.StatusBadRequest) 
   return
          }

   // Do normal API serving
})

However, in some cases I need to return a JSON response to the web client:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    // examine incoming params
    if !ok {
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusBadRequest)
        str := `{"Result":"","Error":"No valide Var"}`
        fmt.Fprint(w, str)
        return
    }

    // Do normal API serving
})

Question is: I want to place the error handling part in a seperate error function and passing what type of error I want to present as a function parameter/method. However I don't know, how to do it semantically.

So, in the gist:

 if isJsonError {
    //call HTTP function to serve JSON error
   }
 if isHTTPError {
   //call HTTP function to serve an HTTP error
}

How can I do that semantically? Sorry in advance, if I'm not being clear. Thank you!

PS: I've also read the following blogpost : http://blog.golang.org/error-handling-and-go

There is a section there called "Simplifying repetitive error handling" - and it's cool but I need to simplify multiple repetitive error handling and I can't figure out how to.

Something like this:

func badReq(w http.ResponseWriter, isJson bool, err string) {
    if !isJson {
        http.Error(w, err, http.StatusBadRequest)
        return
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusBadRequest)
    fmt.Fprintf(w, `{"result":"","error":%q}`, err)
}



http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    if !ok {
        badReq(w, true, "no valid var")
        return
    }
})

The custom handler approach (as per that blog post)—with a func(w http.ResponseWriter, r *http.Request) error signature is certainly a good way to go. You could return &HTTPError{err, code} or a &JSONError{err, code} and have ServeHTTP inspect and render appropriately. eg

type Handler struct {
    h func(http.ResponseWriter, *http.Request) error
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Execute the handler function
    err := h.h(w, r)
    if err != nil {
        switch e := err.(type) {
        case *HTMLError:
             // Render a HTML response, calling e.Err and e.Code
        case *JSONError:
             // Render a JSON response
        default:
             // Handle all other 'generic' errors you don't inspect
        }
    }
}

type HTMLError struct {
    Err error
    Code int
}

func (e *HTMLError) Error() string {
    return e.Err.Error()
}

type JSONError struct {
    Err error
    Code int
}

func (e *JSONError) Error() string {
    return e.Err.Error()
}

func SomeHandler(w http.ResponseWriter, r *http.Request) error {
    // examine incoming params
    if !ok {
        // Your returns are also enforced here - avoiding subtle bugs
        return &HTTPError{errors.New("No good!"), http.StatusBadRequest}
    }
}

Small plug: I wrote a blog post about ways to centralise error handling with handlers that is similar to the example above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM