先用 context.withtimeout() 建立带截止时间的上下文,再用 http.newrequestwithcontext() 创建请求。到期时用 errors.is(err, context.deadlineexceeded) 判断超时。
用本地测试服务制造可控超时
保存为 main.go。服务端等待一秒,客户端只给请求 50 毫秒。
package main
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"time"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-r.Context().Done():
return
case <-time.After(time.Second):
fmt.Fprintln(w, "ok")
}
}))
defer server.Close()
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("request timed out")
return
}
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
defer cancel 会在提前返回时释放上下文关联资源。成功拿到响应时要关闭响应体。
核对超时与正常两条路径
先运行原示例,再把 50*time.Millisecond 改为 2*time.Second 后重跑。
go run main.go
原示例预期输出 request timed out,延长截止时间后预期输出 200。
在 Web 服务里继承来访请求的取消信号
已有 HTTP handler 时,把来访请求的上下文作为父级。
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, upstreamURL, nil)
后续要检查 err。父请求取消后,下游请求可以及时停止。

















