Golang HTTP处理程序 - 请求所需时间

10
我想设置一个计时器来统计服务器完成请求所需的时间,并希望计时器在响应的最后一个字节发送后停止。我发现HTTP服务器只会在处理程序函数返回后才发送响应。是否有办法在响应发送后添加回调?还是有更好的方法来计算从请求的第一个字节到响应的最后一个字节所花费的时间?

你考虑过使用nginx作为go服务器的代理服务器吗?这样可以将所花费的时间记录到nginx访问日志中。 - oldmonk
然而这正是我试图做的,替换nginx... - Artorias
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中的某个地方被写入的,但是高亮显示的点是代码中可以同时获得大约开始时间和结束时间的唯一位置。


那我必须修改标准库才能获取使用的时间吗?这似乎并不是很理想。 - Artorias
最好的选择是使用中间件,否则无法做到。但是所返回的时间将不会像实际写入之间的时间一样准确,而是返回请求/响应处理持续时间。 - John S Perayil
@wachiu 我已经更新了答案,这是你在当前代码中能做到的最好的。 - John S Perayil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接