5

I'm trying to contribute a fix for this issue, and tried something similar to this, but no matter what header I try to set, I don't see it in the http response I am trying to modify.

This is the method I'm trying to change, and here is the line I tried to add :

w.Header().Set("Content-Type", "application/json").

The full method :

func (s *HTTPServer) getServices(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    if err := json.NewEncoder(w).Encode(s.list.GetAllServices()); err != nil {
        log.Println("Error encoding: ", err)
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

I would expect the header to change, but it always is text/plain; charset=utf-8

Disclaimer: this is the first piece of code I wrote (or rather, copy/pasted/adapted) in Go.

Community
  • 1
  • 1
greg0ire
  • 22,714
  • 16
  • 72
  • 101
  • Show the code for the request handler and where you added the call to set the header. – Charlie Tumahai Sep 01 '16 at 14:09
  • I just did I think :) – greg0ire Sep 01 '16 at 14:09
  • 5
    Is the ResponseWriter modified anywhere else before it gets to this function? – Kevin M Granger Sep 01 '16 at 14:11
  • 3
    That looks correct at first glance. Are you sure you're testing the updated code? – JimB Sep 01 '16 at 14:12
  • JimB I just added a log and it does not appear after using the attach trick described in the linked thread, so I'll try again with `--no-cache` – greg0ire Sep 01 '16 at 14:12
  • @KevinMGranger : I don't know, can you explain why that would matter? Do you mean I wouldn't be able to overwrite an existing header? – greg0ire Sep 01 '16 at 14:13
  • You have to be careful that other middleware in the chain hasn't written to the body, since this forces the headers to be written out, after which they can't be modified. – a-h Sep 01 '16 at 14:14
  • 1
    Yay! It finally works! Thanks to the `w.WriteHeader(http.StatusOK)` aacebedo made me add. You can get easy internet points if you want by answering that :) – greg0ire Sep 01 '16 at 14:15
  • Also, I'm moving this logic after the if clause to avoid using json for the error message. – greg0ire Sep 01 '16 at 14:16
  • Thanks a-h, it wasn't the case apparently, but it makes sense! – greg0ire Sep 01 '16 at 14:18

1 Answers1

14

if somebody hit this issue, the next info might be helpful.

the reason this wasn't working is the status code was written out before the attempt to add the content-type header.

to make it work, all headers should be added before w.WriteHeader(status code) is being invoked. example:

w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
encoder := json.NewEncoder(w)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(s.list.GetAllServices()); err != nil {
    panic(err)
}
Itamar Lavender
  • 959
  • 7
  • 20
  • 2
    I ran into the same issue and discovered the same solution, without understanding why it worked. Is there a reference to official go doc, explaining the reason behind this behavior? thanks. – srini Jun 01 '21 at 19:42
  • 1
    This has nothing to do with go, this is how HTTP is designed. as HTTP response status codes indicate whether a specific HTTP request has been successfully completed - hence it has to be the last header before the response body. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html fo more info – Itamar Lavender Jun 02 '21 at 06:30