Golang的http处理程序 – 请求所花费的时间

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

Golang http handler - time taken for request

问题

我正在尝试设置一个计时器,以计算服务器完成一个请求所需的时间,并且我希望计时器在响应的最后一个字节发送后停止。

我发现,在处理程序函数返回之后,HTTP服务器才会发送响应。

是否有办法在响应发送后添加回调函数?

或者是否有更好的方法来计算从请求的第一个字节到响应的最后一个字节发送所花费的时间?

英文:

I am trying to set a timer to count how much time is needed for my server to finish a request and I want the timer to stop after the last byte of the response is sent.

I found that the http server will only send the response after the handler function returns.

Is there any way to add a callback after the response is sent ?

Or is there a better way to count the time taken from the first byte of the request coming in till the last byte byte of the response is sent ?

答案1

得分: 12

更简单但不太准确的方法是使用中间件来包装你的处理函数。

func timer(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        startTime := time.Now()
        h.ServeHTTP(w, r)
        duration := time.Now().Sub(startTime)
    })
}

然后

http.Handle("/route", timer(yourHandler))

这样更准确地计算了处理请求和生成响应所花费的时间,而不是写入之间的时间间隔。


如果你绝对需要更准确的持续时间,那么你要更改的代码部分位于net/http包中。

大概在这里

被标记的行go c.serve(ctx)是启动用于处理请求的Go协程的地方。

for {
    rw, e := l.Accept()
    if e != nil {
        if ne, ok := e.(net.Error); ok && ne.Temporary() {
            if tempDelay == 0 {
                tempDelay = 5 * time.Millisecond
            } else {
                tempDelay *= 2
            }
            if max := 1 * time.Second; tempDelay > max {
                tempDelay = max
            }
            srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
            time.Sleep(tempDelay)
            continue
        }
        return e
    }
    tempDelay = 0

    c := srv.newConn(rw)
    c.setState(c.rwc, StateNew) // before Serve can return

    go func(){
        startTime := time.Now()
        c.serve(ctx)
        duration := time.Now().Sub(startTime)
    }()
}

注意:实际上请求是在net.Conn的某个地方写入的,但是被标记的地方是代码中可以在同一作用域内获得近似的开始时间和结束时间的唯一位置。

英文:

The easier but not as accurate way to do it would be using a middleware to wrap your handler function.

func timer(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()
		h.ServeHTTP(w, r)
		duration := time.Now().Sub(startTime)
	})
}

Then

http.Handle("/route",timer(yourHandler))

This is more accurately the time taken to process the request and form the response and not the time between writes.


If you absolutely need a more accurate duration then the parts of code you're looking to change reside in the net/http package.

It would be around here.

The highlighted line go c.serve(ctx) is where the the go routine for serving the request is spawned.

for {
	rw, e := l.Accept()
	if e != nil {
		if ne, ok := e.(net.Error); ok && ne.Temporary() {
			if tempDelay == 0 {
				tempDelay = 5 * time.Millisecond
			} else {
				tempDelay *= 2
			}
			if max := 1 * time.Second; tempDelay > max {
				tempDelay = max
			}
			srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
			time.Sleep(tempDelay)
			continue
		}
		return e
	}
	tempDelay = 0
    
	c := srv.newConn(rw)
	c.setState(c.rwc, StateNew) // before Serve can return

> go func(){
> startTime := time.Now()
> c.serve(ctx)
> duration := time.Now().Sub(startTime)
> }()

}

Note : The request actually gets written in the net.Conn somewhere inside l.Accept() but the highlighted point is the only place where we can have the approximate start time and end time within the same scope in the code.

huangapple
  • 本文由 发表于 2016年11月15日 12:08:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/40601862.html
匿名

发表评论

匿名网友

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

确定