Golang中的服务器头中间件

huangapple go评论83阅读模式
英文:

Server Header Middleware in Golang

问题

我正在尝试在每个响应中设置服务器头。我尝试使用Gin的中间件来实现这一目标。然而,出于某种原因,这并没有设置头部。到目前为止,我已经尝试过调试,但我无法理解为什么这样不起作用。可能我在这里漏掉了什么。

以下是代码:

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")
}

这是测试输出:

❯ 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 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 &quot;fmt&quot;
import &quot;github.com/gin-gonic/gin&quot;

const SERVER_INFO = &quot;Some-Play-Server&quot;

type ServerHeader struct {
    gin.ResponseWriter
    ServerInfo string
}

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

    return w.ResponseWriter.Write(data)
}

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

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

    fmt.Println(&quot;Server Listening on 0.0.0.0:8080&quot;)
    mux.Run(&quot;:8080&quot;)
}

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)
&gt; GET / HTTP/1.1
&gt; User-Agent: curl/7.30.0
&gt; Host: localhost:8080
&gt; Accept: */*
&gt; 
&lt; HTTP/1.1 200 OK
&lt; Content-Type: text/plain
&lt; Date: Wed, 13 Aug 2014 16:54:21 GMT
&lt; Content-Length: 2
&lt; 
OK

答案1

得分: 5

这里是Gin的创建者:请不要覆盖c.Writer,这会增加很多额外的开销和不必要的复杂性。如果你想要支持透明的gzip压缩或缓存(参见gzip中间件),才需要覆盖writer。如果你只是想要添加一个头部,可以这样做:

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) {
    // 快捷方式,等同于 c.Writer.Header().Set("Server", "Some-Play-Server")
    c.Header("Server", "Some-Play-Server")
}

完成!由于它作为全局中间件附加,所有的响应都会包含Server头部,即使是提供静态文件的时候也是如此!

英文:

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(&quot;/&quot;, func(c *gin.Context) {
        c.String(200, &quot;OK&quot;)
    })    
    mux.Run(&quot;:8080&quot;)
}

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

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

答案2

得分: 3

你没有使用正确的方法来实现这个。

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")
}

以下是输出结果:

$ 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
英文:

You did not use the right method for that ..

package main

import &quot;fmt&quot;
import &quot;github.com/gin-gonic/gin&quot;

const SERVER_INFO = &quot;Some-Play-Server&quot;

type ServerHeader struct {
    gin.ResponseWriter
    ServerInfo string
}

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

    w.ResponseWriter.WriteHeader(code)
}

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

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

    fmt.Println(&quot;Server Listening on 0.0.0.0:8080&quot;)
    mux.Run(&quot;:8080&quot;)
}

Here is the Output

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

答案3

得分: 3

你不需要这样做。
你只需要这样做:

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")
}

另外,请查看最新版本(develop分支),我们对其进行了很多改进。现在gin自动推迟调用WriteHeader(),所以你不需要担心。

英文:

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(&quot;Server&quot;, &quot;Some-Play-Server&quot;)
    })

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

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.

答案4

得分: 2

我不熟悉gin,但是使用内置的http服务器来实现这个功能相对简单:

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))
}

@elithrar在评论中提到了另一种方法,即返回http.Handler

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.ServeHTTP(rw, req)
    })
}

[kbd]playground/kbd

英文:

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

const SERVER_INFO = &quot;Some-Play-Server&quot;
var extra = map[string]string{
	&quot;Server&quot;: 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, &quot;Hello: &quot;+req.URL.String()+&quot;\n&quot;)
	}
	http.HandleFunc(&quot;/&quot;, HeaderSetter(fn))
	log.Panic(http.ListenAndServe(&quot;:9020&quot;, 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)
	})
}

<kbd>playground</kbd>

huangapple
  • 本文由 发表于 2014年8月14日 01:07:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/25292152.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定