在golang中运行X ms后以编程方式关闭http连接

在golang中运行X ms后以编程方式关闭http连接,http,go,timeout,Http,Go,Timeout,我正在执行X个并行http请求,当其中一个请求在X毫秒内没有响应时,想象是100毫秒或更少,我想切断这个连接。我写的代码似乎不起作用,因此,我如何切断连接并得到nil的响应 这是我的示例代码: cx, cancel := context.WithCancel(context.Background()) ch := make(chan *HttpResponse) var responses []*HttpResponse timeout := 1.000 //1ms for testing p

我正在执行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
    }
}

您的代码等待请求完成并获得响应或错误,然后计算所经过的时间,如果时间超过预期时间,您的代码将取消所有请求

    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.
    }

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

你忘了推迟取消,尽管go-vet应该会注意到。谢谢@leafbebop,它似乎可以工作,现在在控制台中我看到上下文截止日期超过了,但它不会继续使用代码,因为它是一个web服务器应用程序。它一直在加载…@xmarston我需要代码的其他部分来知道问题出在哪里。@leadbebebop没事,我没有检查nil响应,所以代码在默默地失败。我纠正了这种行为,现在起作用了。谢谢你的解决方案@xmarston:如果正确处理了错误,就不必检查nil响应。
    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()