golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用

Golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用

这是一个包含中间件的Go库,用于实现HTTP Server-Timing功能。该头部允许服务器从后端发送计时信息,如数据库访问时间、文件读取时间等。这些计时信息可以在标准的浏览器开发者工具中查看:

Server Timing Example

功能特性

  • 中间件用于将服务器计时结构注入请求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
}

代码说明

  1. 中间件设置:使用servertiming.Middleware包装HTTP处理器,它会自动处理Server-Timing头部的注入

  2. 记录计时

    • 通过servertiming.FromContext从请求上下文中获取计时器实例
    • 使用NewMetric()创建新指标
    • 使用Start()Stop()记录代码块的执行时间
    • 可以使用WithDesc()添加描述信息
  3. 并发安全:计时器实例是并发安全的,可以在goroutine中使用

  4. 浏览器查看:运行程序后,在Chrome或Firefox的开发者工具中查看Network标签,点击请求即可看到Server-Timing信息

这个库非常适合用于分析和优化Web应用的性能,特别是在处理多个并发任务或外部服务调用时。


更多关于golang实现HTTP Server-Timing头信息添加与解析插件库go-server-timing的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于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)
}

实际应用场景

  1. 性能监控:跟踪API请求中各个阶段的耗时
  2. 调试:在生产环境中识别性能瓶颈
  3. A/B测试:比较不同实现方式的性能差异
  4. 客户端分析:让客户端了解服务器端处理时间分布

注意事项

  1. Server-Timing 头可能包含敏感信息,生产环境中应考虑过滤或禁用
  2. 过多的指标会增加响应头大小,适度使用
  3. 浏览器开发者工具可以可视化 Server-Timing 信息

通过 go-server-timing 库,我们可以方便地在 Go 应用中添加和解析 Server-Timing 头信息,这对于性能监控和优化非常有帮助。

回到顶部