
Go 的 http.Client 默认会自动跟随重定向,但不会将原始请求中的 Authorization 头(如 Basic Auth)传递到后续跳转请求中,导致 HTTPS 重定向后返回 401 而非预期的 301 或成功响应。
go 的 `http.client` 默认会自动跟随重定向,但不会将原始请求中的 `authorization` 头(如 basic auth)传递到后续跳转请求中,导致 https 重定向后返回 401 而非预期的 301 或成功响应。
在使用 Go 发起带 Basic Auth 的 HTTP 请求时,若目标服务(如 http://aerolith.org/files)首先返回 301 重定向至 HTTPS 地址(https://aerolith.org/files),再进一步重定向至带尾部斜杠的路径(https://aerolith.org/files/),Go 默认的 http.Client 会完整执行这两步重定向 —— 但关键问题在于:它不会自动将 Authorization: Basic ... 头携带到重定向后的请求中。因此,最终对 https://aerolith.org/files/ 的请求因缺少认证信息而被服务器拒绝,返回 401 Unauthorized。
这与 curl 的行为形成鲜明对比:curl 默认不自动跟随重定向(除非显式加 -L 参数),因此你看到的是第一个跳转响应(301),而非最终认证失败的结果。
✅ 正确处理方式:保留认证头并可控重定向
方案一:使用 CheckRedirect 自动补全认证头(推荐)
通过自定义 http.Client.CheckRedirect 函数,在每次重定向前手动设置 Basic Auth,确保认证信息贯穿整个重定向链:
package main
import (
"errors"
"log"
"net/http"
)
func main() {
url := "http://aerolith.org/files"
username := "cesar"
password := "password"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal("创建请求失败:", err)
}
req.SetBasicAuth(username, password)
log.Println("[DEBUG] 已设置 Basic Auth")
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// 防止无限重定向
if len(via) >= 10 {
return errors.New("重定向次数超限(10次)")
}
// 关键:为每个重定向请求重新设置认证头
req.SetBasicAuth(username, password)
return nil
},
}
resp, err := client.Do(req)
if err != nil {
log.Fatal("请求失败:", err)
}
defer resp.Body.Close()
log.Printf("[DEBUG] 响应状态码: %d", resp.StatusCode)
log.Printf("[DEBUG] 响应头: %+v", resp.Header)
}
✅ 优势:语义清晰、符合直觉、支持完整重定向逻辑,且认证安全可控(仅在明确信任的跳转路径中透传)。
方案二:禁用自动重定向,手动控制(类 cURL 行为)
若你只需获取首次响应(如调试 301),可绕过 Client,直接使用底层 http.Transport 执行单次请求:
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
log.Fatal("传输层请求失败:", err)
}
defer resp.Body.Close()
log.Printf("首跳响应码: %d", resp.StatusCode) // 将输出 301
⚠️ 注意:此时需自行解析 Location 头并构造下一次请求,适用于需要完全掌控跳转逻辑的场景(如实现自定义重试策略或审计跳转路径)。
❌ 错误做法:依赖默认 Client + 不处理重定向
// 危险!以下代码将必然导致 401(重定向后认证丢失)
client := &http.Client{} // 无 CheckRedirect 配置
resp, _ := client.Do(req) // 最终请求 https://.../files/ 无 Authorization 头
? 关键注意事项
-
安全性提醒:在 CheckRedirect 中无条件透传 Authorization 头存在风险。若重定向跳转至不受信域(如第三方 URL),可能造成凭据泄露。生产环境建议校验 req.URL.Host 是否与原始域名一致:
if req.URL.Host != "aerolith.org" { return errors.New("拒绝跨域重定向") } - HTTP → HTTPS 跳转是常见诱因:该问题在强制 HTTPS 升级的站点上高频出现,务必检查初始协议与最终目标协议是否一致。
- SetBasicAuth 是覆盖式操作:多次调用会覆盖之前值,无需担心重复设置。
✅ 总结
Go 的 http.Client 默认不传播认证头至重定向请求,这是设计使然(RFC 合规性考量),而非 Bug。解决核心在于:主动介入重定向流程,按需注入认证信息。优先推荐 CheckRedirect 方案,兼顾简洁性与可控性;若需严格模拟 curl -v 的“只看首跳”行为,则选用 RoundTrip。无论哪种方式,都应结合域名白名单与跳转深度限制,兼顾功能性与安全性。











