
go 1.7+ 推荐使用 context.context 配合 http.request.withcontext 实现请求的主动取消,替代已弃用的 cancelrequest;适用于长轮询、用户手动中断等需动态终止请求的场景。
在 Go 中实现 HTTP 请求的客户端主动取消(如用户点击“停止轮询”),关键在于将请求与可取消的 context.Context 绑定。自 Go 1.7 起,http.Transport.CancelRequest 已被正式弃用,官方标准方案是:构造请求时注入带取消能力的上下文,并通过 client.Do() 发起该请求。
✅ 正确做法:使用 WithContext + context.WithCancel
以下是一个完整示例,模拟长轮询场景,并支持外部触发取消:
由于疫情等原因大家都开始习惯了通过互联网上租车服务的信息多方面,且获取方式简便,不管是婚庆用车、旅游租车、还是短租等租车业务。越来越多租车企业都开始主动把租车业务推向给潜在需求客户,所以如何设计一个租车网站,以便在同行中脱颖而出就重要了,易优cms针对租车行业市场需求、目标客户、盈利模式等,进行策划、设计、制作,建设一个符合用户与搜索引擎需求的租车网站源码。 网站首页
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
type ResponseMessage struct {
ID string `json:"id"`
Data string `json:"data"`
}
func longPollWithCancel(client *http.Client, url string, jsonPostBytes []byte) ([]*ResponseMessage, error) {
// 1. 创建可取消的 context
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 注意:此处 defer 不会立即取消,仅确保资源清理;实际取消由外部调用 cancel()
// 2. 构建请求并绑定上下文
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPostBytes))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req = req.WithContext(ctx) // ? 核心:将 context 注入请求
// 3. 发起请求(非阻塞,但后续读取可能阻塞)
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
// 4. 解码响应(此处可能长期阻塞,但 ctx 取消后会立即返回错误)
var results []*ResponseMessage
decoder := json.NewDecoder(resp.Body)
if err := decoder.Decode(&results); err != nil {
// 若因 context 被取消,err 通常为: "context canceled" 或 "net/http: request canceled"
return nil, fmt.Errorf("decode failed: %w", err)
}
return results, nil
}⚠️ 重要注意事项
- resp.Body.Close() 不能直接中断 Decode:它仅关闭连接底层流,但 json.Decoder.Decode 等阻塞读取操作不会因此立即返回——必须依赖 context 才能真正中断。
-
cancel() 必须在另一个 goroutine 中调用:例如监听 UI 事件、信号或超时定时器:
go func() { time.Sleep(5 * time.Second) // 模拟用户 5 秒后点击取消 cancel() }() - 错误判断应检查 context 错误:if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) 是识别取消原因的标准方式(需 Go 1.13+)。
- http.Client 本身无需特殊配置:只要 Transport 支持 context(默认 http.DefaultTransport 在 Go 1.7+ 已支持),即可开箱即用。
✅ 总结
主动取消 HTTP 请求的核心范式是:用 context.WithCancel 或 context.WithTimeout 创建上下文 → 通过 req.WithContext(ctx) 注入请求 → 调用 client.Do(req) → 外部调用 cancel() 即可中断整个请求生命周期(包括 DNS、连接、TLS、发送、接收及响应体读取)。这一机制安全、高效且完全符合 Go 的并发模型,是现代 Go HTTP 客户端开发的必备实践。









