golang实现HTTP客户端Server-Timing头部处理的插件库client-timing的使用

Golang实现HTTP客户端Server-Timing头部处理的插件库client-timing的使用

client-timing是一个用于处理HTTP Server-Timing头部的Golang插件库,它与go-server-timing中间件配合使用。

特性

  • 完全兼容Go标准库的HTTP ClientRoundTripper
  • 自动记录来自HTTP处理程序的请求时间
  • 收集上游服务器的所有计时头信息
  • 根据HTTP请求、响应和错误自定义计时头信息

安装

go get -u github.com/posener/client-timing

使用方法

  1. 在服务器处理程序中添加*clienttiming.Timer,或在处理函数中创建它
  2. servertiming.Middleware包装http.Handler
  3. 在处理函数中:
    • 使用timer.Client(req.Context())创建*http.Client
    • 或使用timer.Transport(req.Context())创建http.RoundTripper
  4. 直接使用上述选项或将它们注入到接受它们的库中
  5. 完成!计时头信息将出现在处理程序的响应中

完整示例

基本结构

type handler struct {
	timer *clienttiming.Timer
}

func main() {
	h := &handler{
		timer: clienttiming.New(clienttiming.WithName("my-server")),
	}
	log.Fatal(http.ListenAndServe(":8080", servertiming.Middleware(h)))
}

使用Client方法

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 使用请求上下文创建HTTP客户端
	c := h.timer.Client(r.Context())

	// 执行HTTP请求,可以执行多个
	resp, err := c.Get("https://golang.org/")

	// 处理响应和错误...
}

使用Transport方法

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 使用计时传输包装HTTP客户端
	c := &http.Client{
		Transport: h.timer.Transport(r.Context()),
	}

	// 执行HTTP请求,可以执行多个
	resp, err := c.Get("https://golang.org/")

	// 处理响应和错误...
}

运行示例

go run ./example/main.go

这个库可以帮助你轻松地在Golang应用中实现HTTP请求的Server-Timing头部处理,便于性能监控和分析。


更多关于golang实现HTTP客户端Server-Timing头部处理的插件库client-timing的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现HTTP客户端Server-Timing头部处理的插件库client-timing的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang HTTP客户端Server-Timing头部处理插件库client-timing使用指南

Server-Timing头部允许服务器在响应中传递性能指标数据,client-timing是一个用于处理这些数据的Golang库。

安装client-timing

go get github.com/posener/client-timing

基本使用方法

1. 创建带Timing的HTTP客户端

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/posener/client-timing"
)

func main() {
	// 创建基础HTTP客户端
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	// 包装客户端以支持Timing
	timingClient := clienttiming.NewClient(client)

	// 创建请求
	req, err := http.NewRequest("GET", "https://example.com", nil)
	if err != nil {
		panic(err)
	}

	// 发送请求并获取响应
	resp, err := timingClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// 获取Timing信息
	timing := clienttiming.Timing(resp)
	fmt.Printf("Timing metrics: %v\n", timing.Metrics())
}

2. 解析Server-Timing头部

Server-Timing头部格式示例:

Server-Timing: miss, db;dur=53, app;dur=47.2

解析代码:

// 获取并解析Server-Timing头部
if timing := clienttiming.Timing(resp); timing != nil {
    metrics := timing.Metrics()
    for _, metric := range metrics {
        fmt.Printf("Metric: %s, Duration: %v, Description: %s\n",
            metric.Name,
            metric.Duration,
            metric.Description)
    }
}

3. 自定义处理Timing数据

// 自定义处理函数
func processTiming(resp *http.Response) {
    timing := clienttiming.Timing(resp)
    if timing == nil {
        return
    }

    // 获取所有指标
    metrics := timing.Metrics()
    
    // 计算总服务器处理时间
    var total time.Duration
    for _, m := range metrics {
        total += m.Duration
    }
    fmt.Printf("Total server processing time: %v\n", total)
    
    // 查找特定指标
    for _, m := range metrics {
        if m.Name == "db" {
            fmt.Printf("Database query took: %v\n", m.Duration)
        }
    }
}

高级用法

1. 自定义HTTP Transport

transport := &http.Transport{
    MaxIdleConns:        10,
    IdleConnTimeout:    30 * time.Second,
    DisableCompression: true,
}

client := &http.Client{
    Transport: transport,
    Timeout:   10 * time.Second,
}

// 包装自定义Transport
timingClient := clienttiming.NewClient(client)

2. 与context集成

func fetchWithTiming(ctx context.Context, url string) {
    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return err
    }

    resp, err := timingClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // 处理Timing数据
    processTiming(resp)
    return nil
}

3. 记录客户端请求时间

// 在请求前记录开始时间
start := time.Now()

resp, err := timingClient.Do(req)
if err != nil {
    return err
}
defer resp.Body.Close()

// 计算总请求时间
totalTime := time.Since(start)

// 获取服务器端时间
serverTiming := clienttiming.Timing(resp)
if serverTiming != nil {
    fmt.Printf("Total request time: %v (client) + %v (server)\n",
        totalTime - serverTiming.Total(),
        serverTiming.Total())
}

实际应用示例

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/posener/client-timing"
)

func main() {
	// 创建带Timing的客户端
	client := clienttiming.NewClient(http.DefaultClient)

	// 测试URL - 可以使用任何返回Server-Timing头部的服务
	url := "https://httpbin.org/response-headers?Server-Timing=miss%2C+db%3Bdur%3D53%2C+app%3Bdur%3D47.2"

	// 发送请求
	resp, err := client.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// 解析Timing数据
	timing := clienttiming.Timing(resp)
	if timing == nil {
		log.Fatal("No Server-Timing header found")
	}

	// 打印所有指标
	fmt.Println("Server Timing Metrics:")
	for _, metric := range timing.Metrics() {
		fmt.Printf("- %s: %v", metric.Name, metric.Duration)
		if metric.Description != "" {
			fmt.Printf(" (%s)", metric.Description)
		}
		fmt.Println()
	}

	// 计算总服务器处理时间
	fmt.Printf("\nTotal server processing time: %v\n", timing.Total())
}

注意事项

  1. 不是所有服务器都支持Server-Timing头部
  2. 生产环境中应考虑添加错误处理和日志记录
  3. 对于性能敏感的应用程序,注意Timing处理的开销
  4. 某些代理服务器可能会移除或修改Server-Timing头部

通过client-timing库,你可以方便地在Golang应用中收集和分析服务器性能指标,这对于性能监控和优化非常有价值。

回到顶部