简体   繁体   中英

Server Header Middleware in Golang

I'm trying to set Server Header on every Response. I'm trying to achieve this, using a Middleware for Gin . However, this does not set the Header, for some reason. I've tried to debug this so far, and I could not understand why this should not work. Probably I'm missing something here.

Here is the code

package main

import "fmt"
import "github.com/gin-gonic/gin"

const SERVER_INFO = "Some-Play-Server"

type ServerHeader struct {
    gin.ResponseWriter
    ServerInfo string
}

func (w *ServerHeader) Write(data []byte) (int, error) {
    if w.Header().Get("Server") == "" {
        w.Header().Add("Server", w.ServerInfo)
    }

    return w.ResponseWriter.Write(data)
}

func InitServerHeader() gin.HandlerFunc {
    return func(c *gin.Context) {
        writer := &ServerHeader{c.Writer, SERVER_INFO}
        c.Writer = writer
        c.Next()
    }
}

func main() {
    mux := gin.Default()
    mux.Use(InitServerHeader())
    mux.GET("/", func(c *gin.Context) {
        c.String(200, "OK")
    })

    fmt.Println("Server Listening on 0.0.0.0:8080")
    mux.Run(":8080")
}

And, here is the Test Output

❯ curl -v http://localhost:8080/
* About to connect() to localhost port 8080 (#0)
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Wed, 13 Aug 2014 16:54:21 GMT
< Content-Length: 2
< 
OK

I'm not familiar with gin, however using the built in http server it's rather trivial to do that:

const SERVER_INFO = "Some-Play-Server"
var extra = map[string]string{
    "Server": SERVER_INFO,
}

func HeaderSetter(fn func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
    return func(rw http.ResponseWriter, req *http.Request) {
        for k, v := range extra {
            rw.Header().Set(k, v)
        }
        fn(rw, req)
    }
}

func main() {
    fn := func(rw http.ResponseWriter, req *http.Request) {
        io.WriteString(rw, "Hello: "+req.URL.String()+"\n")
    }
    http.HandleFunc("/", HeaderSetter(fn))
    log.Panic(http.ListenAndServe(":9020", nil))
}

A different approach was mentioned by @elithrar in the comments is to return http.Handler instead:

func HeaderSetter(fn http.Handler) http.Handler {
    return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        for k, v := range extra {
            rw.Header().Set(k, v)
        }
        fn(rw, req)
    })
}

playground

here Gin's creator: DO NOT override the c.Writer, that's too much overhead and uneeded complexity. The writer should be overrided if you want to support transparent gzip compression or caching (see gzip middleware). If you want to add a header just do this:

func main() {
    mux := gin.Default()
    mux.Use(serverHeader)
    mux.GET("/", func(c *gin.Context) {
        c.String(200, "OK")
    })    
    mux.Run(":8080")
}

func serverHeader(c *gin.Context) {
    // shortcut for c.Writer.Header().Set("Server", "Some-Play-Server")
    c.Header("Server", "Some-Play-Server")
}

Done! since it is attached as a global middleware, all the responses will include the Server header, even when serving static files!

you do not have to do that. You just have to do this:

func main() {
    mux := gin.Default()
    mux.Use(func(c *gin.Context) {
        c.Writer.Header().Set("Server", "Some-Play-Server")
    })

    mux.GET("/", func(c *gin.Context) {
        c.String(200, "OK")
    })    
    mux.Run(":8080")
}

Also, check out the last version (develop branch), we improved it a lot. Now gin automatically defers the call to WriteHeader() so you do not have to worry.

You did not use the right method for that ..

package main

import "fmt"
import "github.com/gin-gonic/gin"

const SERVER_INFO = "Some-Play-Server"

type ServerHeader struct {
    gin.ResponseWriter
    ServerInfo string
}

func (w *ServerHeader) WriteHeader(code int) {
    if w.Header().Get("Server") == "" {
        w.Header().Add("Server", w.ServerInfo)
    }

    w.ResponseWriter.WriteHeader(code)
}

func InitServerHeader() gin.HandlerFunc {
    return func(c *gin.Context) {
        writer := &ServerHeader{c.Writer, SERVER_INFO}
        c.Writer = writer
        c.Next()
    }
}

func main() {
    mux := gin.Default()
    mux.Use(InitServerHeader())
    mux.GET("/", func(c *gin.Context) {
        c.String(200, "OK")
    })

    fmt.Println("Server Listening on 0.0.0.0:8080")
    mux.Run(":8080")
}

Here is the Output

$ curl -v 'http://localhost:8080/'
* About to connect() to localhost port 8080 (#0)
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Server: Some-Play-Server
< Date: Thu, 14 Aug 2014 00:41:27 GMT
< Content-Length: 2
< 
OK

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