golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用
Golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用
这是一个包含中间件的Go库,用于实现HTTP Server-Timing功能。该头部允许服务器从后端发送计时信息,如数据库访问时间、文件读取时间等。这些计时信息可以在标准的浏览器开发者工具中查看:
功能特性
- 中间件用于将服务器计时结构注入请求Context中,并写入Server-Timing头部
- 并发安全的结构,可以轻松记录多个并发任务的计时
- 作为客户端解析Server-Timing头部
- 注意:目前所有浏览器都不支持将Server-Timing头部作为HTTP Trailer发送,因此中间件目前仅支持普通头部
浏览器支持
浏览器支持是轻松查看服务器计时的必要条件。由于服务器计时是作为HTTP头部发送的,因此向不支持的浏览器发送该头部不会产生负面影响。
- 需要Chrome 65或更高版本,或Firefox 71或更高版本才能在开发者工具中正确显示服务器计时
- IE、Opera和其他浏览器目前未知是否支持
使用示例
下面是一个完整的使用示例,演示如何在Go应用中添加Server-Timing头信息:
package main
import (
"fmt"
"math/rand"
"net/http"
"sync"
"time"
"github.com/mitchellh/go-server-timing"
)
func main() {
// 我们的处理器。在实际应用中,这可能是您的根路由器或路由器的一部分
var h http.Handler = http.HandlerFunc(handler)
// 用服务器计时中间件包装我们的处理器
h = servertiming.Middleware(h, nil)
// 启动服务器!
http.ListenAndServe(":8080", h)
}
func handler(w http.ResponseWriter, r *http.Request) {
// 从上下文中获取我们的计时头部构建器
timing := servertiming.FromContext(r.Context())
// 假设您的处理器在goroutine中执行一些任务,例如访问某些远程服务
// timing是并发安全的,因此我们可以记录需要多长时间
// 让我们模拟向各种服务发出5个并发请求
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
name := fmt.Sprintf("service-%d", i)
go func(name string) {
// 创建一个新的指标并启动计时器
// Stop是延迟的,因此当函数退出时会记录持续时间
defer timing.NewMetric(name).Start().Stop()
time.Sleep(random(25, 75))
wg.Done()
}(name)
}
// 假设这只是主处理器中的一些阻塞代码,例如SQL查询
// 让我们记录下来
m := timing.NewMetric("sql").WithDesc("SQL查询").Start()
time.Sleep(random(20, 50))
m.Stop()
// 等待goroutine结束
wg.Wait()
// 您可以继续记录更多指标,但现在让我们返回
w.WriteHeader(200)
w.Write([]byte("完成。请检查浏览器检查器的计时详情。"))
}
func random(min, max int) time.Duration {
return (time.Duration(rand.Intn(max-min) + min)) * time.Millisecond
}
代码说明
-
中间件设置:使用
servertiming.Middleware
包装HTTP处理器,它会自动处理Server-Timing头部的注入 -
记录计时:
- 通过
servertiming.FromContext
从请求上下文中获取计时器实例 - 使用
NewMetric()
创建新指标 - 使用
Start()
和Stop()
记录代码块的执行时间 - 可以使用
WithDesc()
添加描述信息
- 通过
-
并发安全:计时器实例是并发安全的,可以在goroutine中使用
-
浏览器查看:运行程序后,在Chrome或Firefox的开发者工具中查看Network标签,点击请求即可看到Server-Timing信息
这个库非常适合用于分析和优化Web应用的性能,特别是在处理多个并发任务或外部服务调用时。
更多关于golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用 go-server-timing 实现 HTTP Server-Timing 头信息
Server-Timing 是一个 HTTP 响应头,它允许服务器在响应中发送性能指标信息,客户端可以读取这些信息用于性能分析和监控。下面我将介绍如何使用 go-server-timing 库来实现 Server-Timing 头的添加与解析。
安装 go-server-timing
首先安装 go-server-timing 库:
go get github.com/mitchellh/go-server-timing
基本使用方法
1. 添加 Server-Timing 头信息
package main
import (
"net/http"
"time"
"github.com/mitchellh/go-server-timing"
)
func main() {
// 创建新的 Server-Timing 中间件
timing := servertiming.NewMiddleware()
// 设置处理函数
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 从请求上下文中获取 Server-Timing 对象
timing := servertiming.FromContext(r.Context())
// 添加计时指标
metric := timing.NewMetric("db").WithDesc("Database query").Start()
time.Sleep(100 * time.Millisecond) // 模拟数据库查询
metric.Stop()
// 添加自定义值指标
timing.NewMetric("cache").WithDesc("Cache hit").WithDur(50 * time.Millisecond)
w.Write([]byte("Hello, World!"))
})
// 使用中间件包装处理函数
http.Handle("/", timing.Wrap(handler))
http.ListenAndServe(":8080", nil)
}
2. 解析 Server-Timing 头信息
客户端可以解析 Server-Timing 头信息:
package main
import (
"fmt"
"net/http"
"github.com/mitchellh/go-server-timing"
)
func main() {
resp, err := http.Get("http://localhost:8080")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 解析 Server-Timing 头
timingHeader := resp.Header.Get("Server-Timing")
metrics, err := servertiming.Parse(timingHeader)
if err != nil {
panic(err)
}
// 打印所有指标
for _, metric := range metrics {
fmt.Printf("Metric: %s, Duration: %v, Description: %s\n",
metric.Name, metric.Duration, metric.Description)
}
}
高级用法
1. 嵌套计时
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timing := servertiming.FromContext(r.Context())
// 外层计时
outer := timing.NewMetric("total").Start()
defer outer.Stop()
// 内层计时1
inner1 := timing.NewMetric("step1").Start()
time.Sleep(50 * time.Millisecond)
inner1.Stop()
// 内层计时2
inner2 := timing.NewMetric("step2").Start()
time.Sleep(30 * time.Millisecond)
inner2.Stop()
w.Write([]byte("Done"))
})
2. 使用多个中间件
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start)
// 添加日志时间到 Server-Timing
if timing := servertiming.FromContext(r.Context()); timing != nil {
timing.NewMetric("logging").WithDur(duration).WithDesc("Logging middleware")
}
})
}
func main() {
timing := servertiming.NewMiddleware()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello with logging!"))
})
// 组合中间件
http.Handle("/", loggingMiddleware(timing.Wrap(handler)))
http.ListenAndServe(":8080", nil)
}
实际应用场景
- 性能监控:跟踪API请求中各个阶段的耗时
- 调试:在生产环境中识别性能瓶颈
- A/B测试:比较不同实现方式的性能差异
- 客户端分析:让客户端了解服务器端处理时间分布
注意事项
- Server-Timing 头可能包含敏感信息,生产环境中应考虑过滤或禁用
- 过多的指标会增加响应头大小,适度使用
- 浏览器开发者工具可以可视化 Server-Timing 信息
通过 go-server-timing 库,我们可以方便地在 Go 应用中添加和解析 Server-Timing 头信息,这对于性能监控和优化非常有帮助。