重写 http.Server.Serve

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

Overriding http.Server.Serve

问题

我需要在自己的服务器结构中嵌入默认的http.Server并自定义Serve方法。

服务器需要在仅在有计算资源可用以在50毫秒内响应时才运行go c.serve()这一行代码。否则,服务器将只发送一个204状态码并继续执行。

这个问题几乎是直接的。

type PragmaticServer struct {
    http.Server
    Addr    string
    Handler http.Handler
}

func (srv *PragmaticServer) Serve(l net.Listener) error {
    defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    for {
        // 省略部分代码以保持清晰
        c, err := srv.newConn(rw)
        if err != nil {
            continue
        }
        c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve()
    }
}

所以,再说一遍。这几乎可以工作。但是srv.newConnc.servec.setState都是未导出的方法,这意味着我不得不复制并粘贴net/http的大部分代码才能使其编译通过。这基本上是一个分支。有没有更好的方法来解决这个问题?

英文:

I need to embed the default http.Server in my own server struct and customize the Serve method.

The server needs to short circuit the go c.serve() call and only run that line if it has the computing resources available to respond within 50ms. Otherwise the server is just going to send a 204 and move on.

This is almost straightforward.

type PragmaticServer struct {
    http.Server
    Addr    string
    Handler http.Handler
}

func (srv *PragmaticServer) Serve(l net.Listener) error {
	defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    for {
        // SNIP for clarity
    	c, err := srv.newConn(rw)
	    if err != nil {
		    continue
	    }
	    c.setState(c.rwc, StateNew) // before Serve can return
	    go c.serve()
    }
}

So, again. This almost works. Except that srv.newConn is an unexported method, as is c.serve and c.setState, which means that I end up having to copy and paste pretty much the entirety of net/http in order for this to compile. Which is basically a fork. Is there any better way to do this?

答案1

得分: 4

很抱歉,你要重新实现大部分服务器代码才能做到这一点。除此之外,我们通常会在conn.Accept之前或者Handler.ServerHTTP之后拦截调用。

第一种方法是创建一个自定义的net.Listener,在将连接交给http.Server之前过滤掉它们。虽然这样可以更快地响应并且消耗更少的资源,但它会使编写HTTP响应变得不太方便,并且无法限制已经打开的连接上的请求。

第二种处理方法是在真正开始处理之前拦截请求,只需包装处理程序即可。你可能需要创建一个http.Handler来过滤请求,并将它们传递给主处理程序。这种方法也更加灵活,因为你可以根据路由或其他请求信息进行过滤。

英文:

Unfortunately, you're not going to be able to do that without reimplementing most of the Server code. Short of that, we usually intercept the call either just before at conn.Accept, or just after at Handler.ServerHTTP.

The first method is to create a custom net.Listener that filters out connections before they are even handed off to the http.Server. While this can respond faster, and consume fewer resources, it however makes it less convenient to write http responses, and precludes you from limiting requests on already open connections.

The second way to handle this, is to just wrap the handlers and intercept the request before any real work has been done. You most likely want to create a http.Handler to filter the requests, and pass them through to your main handler. This can also be more flexible, since you can filter based on the route, or other request information if you so choose.

huangapple
  • 本文由 发表于 2015年7月28日 22:17:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/31679000.html
匿名

发表评论

匿名网友

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

确定