Go 的 net/http 默认自动处理 301/302 重定向(最多 10 次),可通过配置 http.Client 的 CheckRedirect 字段手动控制:设为 nil 或返回 http.ErrUseLastResponse 可禁用自动跳转并获取原始 3xx 响应;在回调中可审计路径、限制域名、添加请求头;完整跳转链需结合禁用重定向与循环请求实现。

Go 的 net/http 默认会自动处理 301/302 重定向(最多 10 次),但有时你需要手动控制跳转逻辑、查看中间响应、或禁用自动重定向。关键在于配置 http.Client 的 CheckRedirect 字段。
默认行为:自动跟随跳转
不额外配置时,http.Get 或 http.Do 会自动处理 3xx 响应,并返回最终目标的响应体:
resp, err := http.Get("https://httpbin.org/redirect/1")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// resp.StatusCode 是 200(最终页面),不是 302
禁用自动重定向
将 CheckRedirect 设为 nil 或返回 http.ErrUseLastResponse,即可保留原始跳转响应:
- 方法一:设为
nil
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // 停止重定向,返回 301/302 响应
},
}
resp, err := client.Get("https://httpbin.org/redirect-to?url=https://httpbin.org/get")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.StatusCode) // 输出 302
fmt.Println(resp.Header.Get("Location")) // 输出重定向目标地址
自定义跳转逻辑(如记录路径、限制次数、改写请求头)
在 CheckRedirect 回调中可访问每次跳转的请求和历史路径,适合审计、调试或条件跳转:
立即学习“go语言免费学习笔记(深入)”;
- 打印每次跳转的 URL 和状态码
- 只允许跳转到同一域名下(防止开放重定向)
- 添加统一 User-Agent 或 Authorization 头
var redirectLog []string
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
redirectLog = append(redirectLog, fmt.Sprintf("%d → %s", via[len(via)-1].Response.StatusCode, req.URL.String()))
// 示例:只允许同域跳转
if req.URL.Hostname() != "httpbin.org" {
return fmt.Errorf("redirect to disallowed host: %s", req.URL.Host)
}
// 示例:手动添加请求头(原请求头不会自动继承)
req.Header.Set("X-From-Go-Client", "true")
return nil // 继续跳转
},
}
获取完整跳转链(所有中间响应)
标准 http.Client 不直接暴露中间响应,但可通过自定义 Transport 或分步发起请求实现。更实用的方式是用 CheckRedirect 记录跳转路径,再对每个 URL 单独发 HEAD/GET 请求(注意避免副作用):
- 先用禁用重定向的 client 获取第一个 Location
- 循环请求每个 Location,直到状态码非 3xx
- 每步都检查
resp.Header.Get("Location")
这种方式可控性强,适合爬虫、安全检测或调试重定向环。










