Golang中如何计算发送HTTP请求时的代理延迟?

Golang中如何计算发送HTTP请求时的代理延迟? 众所周知,我们可以通过使用 ClientTrace 轻松获取 HTTP 请求的持续时间详情,例如 DNS 时间、TTFB 等。但是,如果我在发送请求时使用了代理服务器呢?据我所知,ClientTrace 没有用于计算代理服务器延迟的钩子。是否有其他方法可以从总请求持续时间中排除代理服务器延迟?

我想要实现的目标:

不使用代理的生命周期:

Client --- request_duration --->  Server
Client <-- response_duration ---  Server

使用代理的生命周期:

Client --- request_proxy_latency  ---> Proxy --- request_duration --->  Server
Client <-- response_proxy_latency ---- Proxy <-- response_duration ---  Server

在上述两种情况下,我只想计算 request_duration + response_duration


更多关于Golang中如何计算发送HTTP请求时的代理延迟?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

看起来没有办法提取代理的延迟。

更多关于Golang中如何计算发送HTTP请求时的代理延迟?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我认为你可以在客户端计算时间。

例如,伪代码可能如下所示

start:=time.Now()
request.get();
end:=time.Now();

所以 (end-start) 将包含请求持续时间加上响应持续时间。

可以通过在代理连接前后添加计时器来测量代理延迟。以下是一个示例实现:

package main

import (
    "context"
    "fmt"
    "net/http"
    "net/http/httptrace"
    "time"
)

type ProxyLatencyTracker struct {
    proxyStart    time.Time
    proxyEnd      time.Time
    requestStart  time.Time
    requestEnd    time.Time
    proxyLatency  time.Duration
    serverLatency time.Duration
}

func (t *ProxyLatencyTracker) createTrace() *httptrace.ClientTrace {
    return &httptrace.ClientTrace{
        GetConn: func(hostPort string) {
            t.proxyStart = time.Now()
        },
        GotConn: func(info httptrace.GotConnInfo) {
            t.proxyEnd = time.Now()
            t.proxyLatency = t.proxyEnd.Sub(t.proxyStart)
            t.requestStart = time.Now()
        },
        GotFirstResponseByte: func() {
            t.requestEnd = time.Now()
            t.serverLatency = t.requestEnd.Sub(t.requestStart)
        },
    }
}

func main() {
    proxyURL, _ := url.Parse("http://proxy.example.com:8080")
    transport := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
    }

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

    tracker := &ProxyLatencyTracker{}
    req, _ := http.NewRequest("GET", "http://example.com", nil)
    ctx := httptrace.WithClientTrace(req.Context(), tracker.createTrace())
    req = req.WithContext(ctx)

    start := time.Now()
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("请求失败: %v\n", err)
        return
    }
    defer resp.Body.Close()

    totalDuration := time.Since(start)
    serverDuration := tracker.serverLatency

    fmt.Printf("总耗时: %v\n", totalDuration)
    fmt.Printf("代理延迟: %v\n", tracker.proxyLatency)
    fmt.Printf("服务器处理时间: %v\n", serverDuration)
    fmt.Printf("实际请求响应时间 (排除代理): %v\n", serverDuration)
}

对于更精确的测量,可以自定义 Transport 实现:

type TrackingTransport struct {
    Transport http.RoundTripper
    ProxyLatency  time.Duration
    RequestStart  time.Time
}

func (t *TrackingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    // 记录代理连接开始时间
    proxyStart := time.Now()
    
    // 执行实际的请求
    t.RequestStart = time.Now()
    resp, err := t.Transport.RoundTrip(req)
    
    // 计算代理延迟
    t.ProxyLatency = t.RequestStart.Sub(proxyStart)
    
    return resp, err
}

func main() {
    proxyURL, _ := url.Parse("http://proxy.example.com:8080")
    baseTransport := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
    }
    
    trackingTransport := &TrackingTransport{
        Transport: baseTransport,
    }
    
    client := &http.Client{
        Transport: trackingTransport,
    }
    
    req, _ := http.NewRequest("GET", "http://example.com", nil)
    
    start := time.Now()
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("请求失败: %v\n", err)
        return
    }
    defer resp.Body.Close()
    
    totalDuration := time.Since(start)
    actualDuration := totalDuration - trackingTransport.ProxyLatency
    
    fmt.Printf("总耗时: %v\n", totalDuration)
    fmt.Printf("代理延迟: %v\n", trackingTransport.ProxyLatency)
    fmt.Printf("实际请求响应时间: %v\n", actualDuration)
}

如果需要区分请求和响应的代理延迟,可以使用连接前后的时间戳:

type DetailedProxyTracker struct {
    ConnectStart     time.Time
    ConnectDone      time.Time
    RequestSent      time.Time
    ResponseReceived time.Time
}

func (t *DetailedProxyTracker) WrapTransport(transport http.RoundTripper) http.RoundTripper {
    return &detailedTransport{
        Transport: transport,
        tracker:   t,
    }
}

type detailedTransport struct {
    Transport http.RoundTripper
    tracker   *DetailedProxyTracker
}

func (t *detailedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    t.tracker.ConnectStart = time.Now()
    
    // 模拟连接建立
    connStart := time.Now()
    // 这里可以添加实际的连接逻辑
    time.Sleep(10 * time.Millisecond) // 模拟连接时间
    t.tracker.ConnectDone = time.Now()
    
    t.tracker.RequestSent = time.Now()
    resp, err := t.Transport.RoundTrip(req)
    t.tracker.ResponseReceived = time.Now()
    
    return resp, err
}

这些方法通过测量代理连接建立时间和实际请求开始时间的差值来计算代理延迟,从而从总时间中排除代理服务器的处理时间。

回到顶部