
本文详解 Go net/http 客户端默认重定向行为、手动禁用重定向后提取 Location 头的方法,并提供可直接运行的代码示例与关键注意事项。
本文详解 go `net/http` 客户端默认重定向行为、手动禁用重定向后提取 `location` 头的方法,并提供可直接运行的代码示例与关键注意事项。
在 Go 中,http.Client 默认会自动跟随 HTTP 3xx 重定向(最多 10 次),并最终返回重定向链末端的响应。这正是你遇到 unexpected EOF 的根本原因:当服务端返回 302 Moved Temporarily 并设置 Connection: close 时,若客户端未显式禁用重定向,它会尝试继续发起新请求;但若目标不可达、网络异常或服务端提前关闭连接,就可能触发底层 I/O 错误(如 unexpected EOF),而非返回原始重定向响应。
要捕获并解析原始重定向响应中的 Location 头,必须禁用自动重定向机制。核心步骤如下:
✅ 正确做法:禁用重定向 + 手动提取 Location
func CheckURL(url string) (string, error) {
// 禁用自动重定向:设置 CheckRedirect 为 nil 或返回 http.ErrUseLastResponse
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // 关键:停止跟随,返回当前响应
},
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
// 检查是否为重定向状态码(3xx)
if resp.StatusCode >= 300 && resp.StatusCode <h3>⚠️ 注意事项</h3>
-
resp.Location()仅在响应头中存在合法Location字段时才返回有效 URL;若缺失或格式错误,会返回解析错误(如parse "": empty url)。 -
http.ErrUseLastResponse是标准方式,明确告知客户端“使用本次响应,不再重定向”;切勿返回nil(这等价于启用默认重定向)。 - 始终调用
resp.Body.Close()防止连接泄漏,尤其在非 2xx 响应时易被忽略。 - 若需自定义重定向逻辑(如限制跳转次数、校验跳转域名),可实现
CheckRedirect回调函数,而非完全禁用。
? 补充说明:默认行为为何导致问题?
你的原始代码使用 client.Get(url),等价于 client.Do(&http.Request{...}),而默认 http.DefaultClient 的 CheckRedirect 为 defaultCheckRedirect —— 它会无条件跟随重定向。当服务端返回 302 并主动关闭连接(Connection: close)时,Go 客户端在尝试读取后续响应体时遭遇连接中断,从而抛出 unexpected EOF。此时你根本拿不到原始响应对象,更无法访问 Location。
因此,显式控制重定向行为是获取重定向元信息的前提。掌握 CheckRedirect 和 resp.Location() 的组合使用,即可精准掌控 HTTP 跳转流程,满足健康检查、URL 归一化、爬虫跳转分析等实际场景需求。










