Golang Context Done信号如何实现请求取消?代码逻辑疑问解析
Great question! Let's unpack this code and the mechanism step by step to clear up your confusion.
First, let's start with the most critical line that makes the cancellation work:
req = req.WithContext(ctx)
This creates a new copy of the HTTP request bound to the provided ctx. The Go standard library's http.Client.Do method is built to listen for signals from the request's context. When ctx.Done() is closed (either via an explicit cancel call, timeout, or deadline), the Do method will immediately interrupt the ongoing HTTP request: it closes the underlying TCP connection, stops waiting for the server's response, and returns an error indicating the context was canceled. This is where the actual request cancellation happens—before we even get to the select block.
Now let's walk through the rest of the code to see how it all ties together:
The goroutine runs
c <- f(http.DefaultClient.Do(req)):- When the context is canceled,
Do(req)quickly returns a cancellation error instead of blocking indefinitely. - The function
fthen processes this error (or a successful response if the request finished before cancellation), and sends the result to thecchannel.
- When the context is canceled,
The
selectblock handles two cases:- Case 1:
<-ctx.Done()triggers first: This means the context was canceled before the request/processing finished. We still do<-chere to wait forfto complete its work—this prevents goroutine leaks, as we need to ensure the goroutine exits cleanly before returning. After that, we returnctx.Err()to let the caller know the operation was canceled due to the context. - Case 2:
err := <-ctriggers first: This means the request andf's processing finished before the context was canceled. We just return the resulting error (ornilif everything worked).
- Case 1:
Your confusion about "waiting for the request result even after the context is done" makes sense at first glance, but remember: by the time <-ctx.Done() is triggered, the Do method has already been told to cancel the request. The <-c is just waiting for the cleanup (the f function to finish) to complete, not waiting for a full, successful response from the server. The request itself is no longer in progress—it's already been terminated by the context signal.
内容的提问来源于stack exchange,提问作者Jeff P Chacko

