
go 标准库的 `http.client` 默认会自动处理重定向,且在跳转前丢弃原始响应体;若需访问首次响应的状态码、header 或 body,必须禁用自动重定向并手动实现跳转逻辑。
在 Go 中,http.Client 默认启用自动重定向(通过 CheckRedirect 控制跳转策略),但其内部实现会在检测到重定向响应(如 301、302)后立即关闭原始响应体(resp.Body.Close())并丢弃内容,仅保留跳转所需的 Location 头信息。这意味着:即使你设置了 CheckRedirect 回调,也无法在回调中读取原始响应的 Body 或完整 Header —— 因为此时 resp.Body 已被关闭或已部分读取。
✅ 正确做法:禁用自动重定向,手动控制流程
你需要将 Client.CheckRedirect 设为 nil(或返回 http.ErrUseLastResponse),从而阻止 Client.Do() 自动跳转,然后自行解析响应、读取内容,并决定是否发起下一次请求:
由于疫情等原因大家都开始习惯了通过互联网上租车服务的信息多方面,且获取方式简便,不管是婚庆用车、旅游租车、还是短租等租车业务。越来越多租车企业都开始主动把租车业务推向给潜在需求客户,所以如何设计一个租车网站,以便在同行中脱颖而出就重要了,易优cms针对租车行业市场需求、目标客户、盈利模式等,进行策划、设计、制作,建设一个符合用户与搜索引擎需求的租车网站源码。 网站首页
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // 关键:停止自动重定向
},
}
req, _ := http.NewRequest("GET", "https://httpbin.org/redirect/1", nil)
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// ✅ 此时可安全读取首次响应的全部信息
fmt.Printf("Status: %s\n", resp.Status) // e.g. "302 Found"
fmt.Printf("Location: %s\n", resp.Header.Get("Location")) // e.g. "/get"
fmt.Printf("Content-Length: %d\n", resp.ContentLength)
// 若需读取 Body(注意:重定向响应 Body 通常较小,但需显式读取)
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Raw body: %s\n", string(body))⚠️ 注意事项
- http.ErrUseLastResponse 是唯一可靠方式:它告诉 Client.Do() 在收到重定向响应时直接返回当前 *http.Response,而非继续跳转。
- 不要依赖 CheckRedirect 获取响应:该回调参数中不包含 *http.Response,仅提供即将发出的 *http.Request 和历史请求链 via,无法回溯响应数据。
- Body 必须及时读取并关闭:即使不消费 Body,也建议用 io.CopyN(ioutil.Discard, resp.Body, ...) 或 io.ReadAll 显式处理,避免连接复用异常(尤其对小响应体)。
- 手动重定向需校验安全性:若需模拟完整重定向逻辑(如处理 307/308 方法保持),需自行复制 Header、Body 并重建请求,注意 Authorization、Cookie 等敏感头的传递策略。
? 总结
Go 的 net/http 并未暴露重定向过程中的中间响应对象。要访问首次响应,核心原则是:*关闭自动重定向 → 拿到 `http.Response` → 立即读取所需字段与 Body → 按需手动发起后续请求**。这是一种更底层但完全可控的方式,适用于调试、审计、合规日志等需要完整 HTTP 事务可见性的场景。









