Set http headers for multiple handlers in go

I am trying to set an HTTP header for multiple handlers. My first thought was to create a custom post function that would set a title before writing an answer, like the code example below.

However, when I pass a pointer to http.ResponseWriter and try to access it from my function, it tells me that "type * http.ResponseWriter does not have a header method."

What is the best way to set the headers for multiple handlers, and why doesn't the pointer work the way I want?

func HelloServer(w http.ResponseWriter, req *http.Request) { type Message struct { Name string Body string Time int64 } m := Message{"Alice", "Hello", 1294706395881547000} b, _ := json.Marshal(m) WriteJSON(&w, b) } func WriteJSON(wr *http.ResponseWriter, rawJSON []byte) { *wr.Header().Set("Content-Type", "application/json") io.WriteString(*wr, string(rawJSON)) } func main() { http.HandleFunc("/json", HelloServer) err := http.ListenAndServe(":9000", nil) if err != nil { log.Fatal("ListenAndServer: ", err) } } 
+4
source share
4 answers

I'm not sure about working with multiple handlers, but I know why the code you wrote fails. The key is that the line:

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

interpreted due to operator precedence, as:

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

Since wr is of type *http.ResponseWriter , which is a to pointer and an interface, not the interface itself, this will not work. I assume you knew this, so you did *wr . I assume you meant the compiler:

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

If I am not mistaken, this should compile and behave correctly.

+4
source

You do not need to use *wr since it already refers to a pointer.

wr.Header().Set("Content-Type", "application/json") should be enough.

If you want to set β€œglobal” headers for each request, you can create a function that satisfies http.HandleFunc ( go.auth has a good example ), and then wrap your handlers like this:

http.HandleFunc("/hello", Defaults(helloHandler))

Also see the net/http documentation for more examples .

+1
source

I port handlers to an error handler that calls my AddSafeHeader function.

I based it on http://golang.org/doc/articles/error_handling.html but it does not use ServeHTTP, so it works with appstats:

 http.Handle("/", appstats.NewHandler(util.ErrorHandler(rootHandler))) 

Here:

 package httputil import ( "appengine" "net/http" "html/template" ) func AddSafeHeaders(w http.ResponseWriter) { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-XSS-Protection", "1; mode=block") w.Header().Set("X-Frame-Options", "SAMEORIGIN") w.Header().Set("Strict-Transport-Security", "max-age=2592000; includeSubDomains") } // Redirect to a fixed URL type redirectHandler struct { url string code int } func (rh *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Redirect(w, r, rh.url, rh.code) } func Redirect(w http.ResponseWriter, r *http.Request, urlStr string, code int) { AddSafeHeaders(w) http.Redirect(w, r, urlStr, code) } // RedirectHandler returns a request handler that redirects // each request it receives to the given url using the given // status code. func RedirectHandler(url string, code int) http.Handler { return &redirectHandler{url, code} } func ErrorHandler(fn func(appengine.Context, http.ResponseWriter, *http.Request)) func(appengine.Context, http.ResponseWriter, *http.Request) { return func(c appengine.Context, w http.ResponseWriter, r *http.Request) { defer func() { if err, ok := recover().(error); ok { c.Errorf("%v", err) w.WriteHeader(http.StatusInternalServerError) errorTemplate.Execute(w, err) } }() AddSafeHeaders(w) fn(c, w, r) } } // Check aborts the current execution if err is non-nil. func Check(err error) { if err != nil { panic(err) } } var errorTemplate = template.Must(template.New("error").Parse(errorTemplateHTML)) const errorTemplateHTML = ` <html> <head> <title>XXX</title> </head> <body> <h2>An error occurred:</h2> <p>{{.}}</p> </body> </html> ` 
0
source

http.ResponseWriter is an interface.

You should probably not use a pointer to an interface. In net / http / server.go, the undisclosed response structure is the actual type that implements ResponseWriter when the server calls your handler, and, importantly, when the server actually calls the ServeHTTP handler , it passes *response . This is already a pointer, but you do not see it, because ResonseWriter is an interface. (an answer pointer is created here , (c * conn) .readRequest . (The links will probably be for incorrect lines in the future, but you can find them).

This is why the ServeHTTP function needed to implement Handler :

 ServeHTTP(w ResponseWriter, r *Request) 

i.e. not a pointer to a ResponseWriter , because this declaration already allows a pointer to a structure that implements the ResponseWriter interface.

0
source

Source: https://habr.com/ru/post/1491282/


All Articles