用 context.withtimeout 为这次调用创建截止时间,再用 http.newrequestwithcontext 绑定请求。取消范围覆盖连接、发送请求和读取响应,调用结束时用 defer cancel 释放资源。

让本地测试服务故意延迟
保存为 main.go。测试服务器最多等待 300 毫秒,并响应客户端取消。
package main
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
)
func fetch(client *http.Client, url string, timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
response, err := client.Do(req)
if err != nil {
return err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP %d", response.StatusCode)
}
_, err = io.Copy(io.Discard, response.Body)
return err
}
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timer := time.NewTimer(300 * time.Millisecond)
defer timer.Stop()
select {
case <p><img src="https://img.php.cn/upload/image/308/637/208/1794562326505262.jpg?x-oss-process=image/resize,p_40" alt="让本地测试服务故意延迟"></p><p>执行 go run main.go,预期输出 deadline exceeded: true。</p><h2>拉长时限确认正常路径</h2><p>在 main 的结尾追加一次请求。</p><pre class="brush:php;toolbar:false;">err = fetch(server.Client(), server.URL, time.Second)
fmt.Println("request succeeded:", err == nil)
预期新增输出 request succeeded: true。两次调用可以共享同一个 HTTP 客户端。
从入站请求继承取消信号
若 fetch 由 HTTP 处理器调用,给 fetch 增加 parent context.Context 参数,用下面代码替换原先的 context 创建方式。
ctx, cancel := context.WithTimeout(parent, timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
调用时传入入站请求的 r.Context()。上游断开或父级截止时间先到时,子请求也会被取消。










