This article was originally published on bmf-tech.com.
Overview
This is a note about the side effects of Go's response.WriteHeader.
superfluous response.WriteHeader
The following is a straightforward example, but if you call WriteHeader multiple times as shown below, you will get an error: http: superfluous response.WriteHeader call from main.handler.
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.WriteHeader(http.StatusInternalServerError) // Error!
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8888", nil)
}
When called multiple times like this, the status code from the first call is adopted, and the status code from the last call is ignored. (Is it related to HTTP specifications?)
You can get a sense of the specifications by looking at these.
Solution
In the straightforward example above, you can simply adjust the implementation to call WriteHeader only once. However, let's assume there are cases where WriteHeader is set multiple times due to implementation reasons.
import (
"bytes"
"html/template"
"net/http"
)
// Function called for rendering error pages
func ExecuteTpl(w http.ResponseWriter) error {
err := template.Must(template.ParseFiles("index.html")).Execute(w, nil)
w.WriteHeader(http.StatusInternalServerError)
if err != nil {
return err
}
return nil
}
Suppose WriteHeader has already been called before this function, causing an error.
To avoid errors in such situations, you can write to a buffer first and then call WriteHeader at the end.
package main
import (
"bytes"
"html/template"
"net/http"
)
func ExecuteTpl(w http.ResponseWriter) error {
var buf bytes.Buffer
w.WriteHeader(http.StatusInternalServerError)
err := template.Must(template.ParseFiles("index.html")).Execute(w, nil)
if err != nil {
return err
}
buf.WriteTo(w)
return nil
}
Others
When there is an error during the call to template's Execute, execution stops, but it seems that writing to the response may partially start, so it seems better to call WriteHeader before Execute. (Probably)
Top comments (0)