【问题标题】:Close http connection programmatically after X ms in golang在 golang 中 X 毫秒后以编程方式关闭 http 连接
【发布时间】:2018-07-13 19:21:04
【问题描述】:

我正在执行 X 个并行 http 请求,当其中一个在 X 毫秒(假设为 100 毫秒)或更短的时间内没有响应时,我想切断此连接。我写的代码似乎不起作用,我怎样才能切断连接并将响应设为 nil?

这是我的示例代码:

cx, cancel := context.WithCancel(context.Background())
ch := make(chan *HttpResponse)
var responses []*HttpResponse

timeout := 1.000 //1ms for testing purposes
var client = &http.Client{
    Timeout: 1 * time.Second,
}

startTime := time.Now()
for _, url := range urls {
    go func(url string) {
        fmt.Printf("Fetching %s \n", url)
        req, _ := http.NewRequest("POST", url, bytes.NewReader(request)) //request is json string
        req.WithContext(cx)
        resp, err := client.Do(req)
        ch <- &HttpResponse{url, resp, err}
        var timeElapsed = time.Since(startTime)
        msec := timeElapsed.Seconds() * float64(time.Second/time.Millisecond)
        if msec >= timeout {
            cancel()
        }
        if err != nil && resp != nil && resp.StatusCode == http.StatusOK {
            resp.Body.Close()
        }
    }(url)
}

for {
    select {
    case r := <-ch:
        fmt.Printf("%s was fetched\n", r.Url)
        if r.Err != nil {
            fmt.Println("with an error", r.Err)
        }
        responses = append(responses, r)
        if len(responses) == len(*feeds) {
            return responses
        }
    case <-time.After(100):
        //Do something
    }
}

【问题讨论】:

    标签: http go timeout


    【解决方案1】:

    您的代码会等到请求完成(并收到响应或错误),然后计算经过的时间,如果超过预期时间,您的代码将取消所有请求。

        req, _ := http.NewRequest("POST", url, bytes.NewReader(request)) //request is json string
        req.WithContext(cx) //Here you use a common cx, which all requests share.
        resp, err := client.Do(req) //Here the request is being sent and you wait it until done.
        ch <- &HttpResponse{url, resp, err}
        var timeElapsed = time.Since(startTime)
        msec := timeElapsed.Seconds() * float64(time.Second/time.Millisecond)
        if msec >= timeout {
            cancel() //here you cancel all the requests.
        }
    

    解决方法是正确使用context 包。

        req, _ := http.NewRequest("POST", url, bytes.NewReader(request)) //request is json string
        ctx,cancel := context.WithTimeout(request.Context(),time.Duration(timeout)*time.Millisecond)
        resp,err:=client.Do(req.WithContext(ctx))
        defer cancel()
    

    这样,您将得到一个 nil resp(和一个错误)并在超时时切断连接。

    【讨论】:

    • 你忘记了defer cancel(),虽然go vet 应该明白这一点。
    • 感谢@leafbebop,它似乎可以工作,现在在控制台中我看到超出了上下文截止日期,但它没有继续使用代码(它是一个 Web 服务器应用程序)。它一直在加载...
    • @xmarston 我需要代码的其他部分来了解问题所在。
    • @leafbebop 什么都没有,我没有检查 nil 响应,所以代码默默地失败了。我纠正了这种行为,现在就像一个魅力。感谢您的解决方案!
    • @xmarston:如果您正确处理错误,则永远不必检查 nil 响应。
    猜你喜欢
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 2014-06-05
    • 2012-12-16
    • 1970-01-01
    相关资源
    最近更新 更多