Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle superfluous response.WriteHeader call in order to return 500

Tags:

go

I am aware that the WriteHeader method of http.ResponseWriter can only be called once per HTTP response, can only have a single response status code and can only send the headers once. This is all perfectly fine.

The question is, how should I refactor my code in order to override 201 and return 500 if http.ResponseWriter.Write returns an error? As you can see below I force panic on purpose to see how httprouter.Router.PanicHandler handles it. As expected, logs show http: superfluous response.WriteHeader call from ... and the response is 201 because it is too late as explained above.

package server

import (
    "github.com/julienschmidt/httprouter"
    "log"
    "net/http"
)

func Serve() {
    rtr := httprouter.New()
    rtr.GET("/", home.Welcome)

    handle500(rtr)

    err := http.ListenAndServe(":8080", rtr)
    if err != nil {
        log.Fatalf("server crash")
    }
}

func handle500(r *httprouter.Router) {
    r.PanicHandler = func(res http.ResponseWriter, req *http.Request, err interface{}) {
        res.WriteHeader(http.StatusInternalServerError)
        // http: superfluous response.WriteHeader call from line above
    }
}
package home

import (
    "github.com/julienschmidt/httprouter"
    "net/http"
)

func Welcome(res http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
    // doing a few bits and building the body

    res.Header().Set("Content-Type", "application/json")
    res.WriteHeader(201)

    _, err := res.Write("body goes here")
    if err == nil {  // I am doing this deliberately to test 500
        panic("assume that something has gone wrong with res.Write and an error occurred")
    }
}
like image 476
BentCoder Avatar asked Sep 06 '19 21:09

BentCoder


1 Answers

There is no way to "override" the status code as it's sent to the browser immediately.

You're checking for the return value of http.ResponseWriter.Write(). I'm not sure this is a good strategy. If writing the response failed then chances are that writing more will probably fail, too.

Logging the failure seems more appropriate, but I would expect most failures to be dropped connections and other errors which won't require action.

like image 116
Martin Tournoij Avatar answered Nov 04 '22 18:11

Martin Tournoij