doubei5310 2018-02-21 08:01
浏览 163
已采纳

在Go中跟踪HTTP请求时指定超时

I know the usual method of specifying a timeout with HTTP requests by doing:

httpClient := http.Client{
    Timeout: time.Duration(5 * time.Second),
}

However, I can't seem to figure out how to do the same when tracing HTTP requests. Here is the piece of code I am working with:

func timeGet(url string) (httpTimingBreakDown, error) {
    req, _ := http.NewRequest("GET", url, nil)

    var start, connect, dns, tlsHandshake time.Time
    var timingData httpTimingBreakDown
    timingData.url = url

    trace := &httptrace.ClientTrace{
        TLSHandshakeStart:    func() { tlsHandshake = time.Now() },
        TLSHandshakeDone:     func(cs tls.ConnectionState, err error) { timingData.tls = time.Since(tlsHandshake) },
    }

    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
    start = time.Now()

    http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 10 // hacky way, worked earlier but don't work anymore

    if _, err := http.DefaultTransport.RoundTrip(req); err != nil {
        fmt.Println(err)
        return timingData, err
    }

    timingData.total = time.Since(start)

    return timingData, nil
}

I am firing this function inside a goroutine. My sample data set is 100 urls. All goroutines fire, but eventually the program ends in 30+ secs as if the timeout is 30secs.

Earlier I made the same to work by using the hacky way of changing the default inside of it to 10 secs and anything that took too long, timed out and the program ended at 10.xxx secs but now its taking 30.xx secs.

What would be a proper way of specifying a timeout in this scenario?

  • 写回答

1条回答 默认 最新

  • douba9776 2018-02-21 08:27
    关注

    I know the usual method of specifying a timeout with HTTP requests by doing:

    httpClient := http.Client{
        Timeout: time.Duration(5 * time.Second),
    }
    

    Actually, the preferred method is to use a context.Context on the request. The method you've used is just a short-cut suitable for simple use cases.

    req, err := http.NewRequest(http.MethodGet, url, nil)
    if err != nil {
        return nil, err
    }
    ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
    defer cancel()
    req = req.WithContext(ctx)
    

    And this method should work nicely for your situation as well.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献