当前位置:首页 > 文章列表 > Golang > Go教程 > Go net/http Client重定向时降级敏感请求头的处理方案

Go net/http Client重定向时降级敏感请求头的处理方案

来源:17golang原创 2026-09-15 21:53:24 0浏览 收藏

服务端返回 301、302 或 307 时,Go 的 http.Client 不只是换一个 URL:它还会决定哪些请求头进入下一跳。默认策略会保护跨不可信域名的敏感头,但同域、子域以及同一主机换 scheme 的边界并不等同于严格的 origin。要让重定向明确降级,做法是给 Client.CheckRedirect 配置一层 origin 判断,在边界变化时删除凭据头,再决定是否继续。

要点速览
  • 默认规则会对不匹配域名忽略 AuthorizationWWW-AuthenticateCookie,但子域与同主机换 scheme 仍可能保留敏感头。
  • CheckRedirect 收到的是即将发送的请求和历史请求,可用最后一跳比较 scheme、host、端口。
  • 自定义的 X-API-Key 不属于默认保护清单,跨 origin 时应由业务策略显式删除。

官方地址:https://pkg.go.dev/net/http。本文只讨论 Go net/http Client 的重定向请求头边界,不扩展到 HTTP 框架选型。

默认重定向规则为什么不等于严格同源

Client 跟随重定向时,会把初始请求的普通头带到后续请求;对敏感头,默认规则会在目标域名既不是原域名、也不是原域名的子域时忽略它们。例如 api.example.comcdn.example.com 仍属于子域匹配,而到 other.example.net 则不会继续带凭据。

这个规则解决的是“不要把凭据发给完全无关域名”,却不是严格的 origin 策略:同一 host 从 HTTPS 跳到 HTTP,或者从一个端口跳到另一个端口,仍可能落在默认转发范围内。若业务把 scheme、端口也视为信任边界,就需要覆盖 CheckRedirect

Go net/http Client 重定向时按域名匹配转发敏感请求头的静态边界说明图
图1:Go net/http Client 默认重定向规则的边界说明图,不是运行截图或执行证据。

用 CheckRedirect 比较前后请求的 origin

回调里的 req 是即将发送的下一跳,via 按从旧到新的顺序保存已发请求。比较 via 最后一项与 req 的 scheme 和 host,可以得到比“同域或子域”更清晰的同源判定。

package main

import (
    "net/http"
    "strings"
)

// sameOrigin 只把 scheme、主机和端口都相同的地址视为同一信任边界。
func sameOrigin(a, b *http.Request) bool {
    return strings.EqualFold(a.URL.Scheme, b.URL.Scheme) &&
        strings.EqualFold(a.URL.Host, b.URL.Host)
}

// redirectPolicy 读取上一跳请求,再处理即将发送的下一跳请求。
func redirectPolicy(req *http.Request, via []*http.Request) error {
    if len(via) == 0 {
        return nil // 第一跳没有历史请求,不需要比较。
    }
    previous := via[len(via)-1]
    if !sameOrigin(previous, req) {
        // 跨 origin 时删除凭据;X-API-Key 是业务自定义敏感头。
        req.Header.Del("Authorization")
        req.Header.Del("Cookie")
        req.Header.Del("X-API-Key")
    }
    return nil // 返回 nil 才允许 Client 继续跟随重定向。
}

var client = &http.Client{CheckRedirect: redirectPolicy}

这里的策略比默认行为更保守:子域跳转也会清理头,端口变化同样会清理。普通的 User-Agent、追踪 ID 等非凭据头可以继续沿用,但不要把“所有 Header 都安全”作为假设。

跳转情况默认 Client上面策略
同域同 scheme 同端口通常保留敏感头保留
子域或端口变化可能保留清理敏感头
完全不同域名忽略敏感头清理敏感头

自定义 API 密钥要在回调里显式降级

默认保护清单并不知道业务自定义的 X-API-Key、租户签名或内部追踪凭据。只配置 Authorization 的删除是不够的,应该把所有真正代表身份或授权的头集中列入策略。Cookie 还要注意 Jar:有非空 Cookie Jar 时,客户端会在每次重定向前后更新和重新装配 Cookie,不能只依赖初始请求里的 Header。

Go CheckRedirect 比较前后 origin 后清理 Authorization Cookie 和 X-API-Key 的静态关系说明图
图2:CheckRedirect 的 origin 判断、敏感头清理与后续请求关系说明图,不是运行截图。

如果业务根本不接受自动跳转,可以直接停止链路,让上层读取响应的 Location 再做白名单判断:

client := &http.Client{
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
        // 中文注释:到达重定向回调时不再自动发送下一跳,保留最后响应供调用方判断。
        return http.ErrUseLastResponse
    },
}

resp, err := client.Get("https://api.example.com/resource")
if err != nil {
    // 中文注释:网络错误或客户端策略错误都要交给调用方处理。
    return err
}
defer resp.Body.Close() // 中文注释:ErrUseLastResponse 返回的响应体由调用方关闭。
// 中文注释:此处可读取 resp.Location,并按业务白名单决定是否发起新请求。

307/308、响应体和重定向次数的检查清单

301、302、303 通常会把后续方法改成 GET;307、308 会保留原方法和请求体,但前提是 Request.GetBody 可用。上传类请求尤其要确认请求体能否重放,不要因为清理了 Header 就误以为重定向链已经安全。

  • 只允许预期的 scheme、host 和端口,或在 CheckRedirect 中遇到异常直接返回错误。
  • AuthorizationCookie、API 密钥、租户签名等业务凭据列成明确清单。
  • Do 成功返回后读取并关闭 resp.Body;使用 ErrUseLastResponse 时也一样。
  • 复用同一个 http.Client,并为重定向链保留最大次数控制,避免无限跳转消耗请求预算。

相关问题

为什么跳到子域时 Authorization 还在?

这是 Go 默认规则的一部分:同域或子域匹配时允许转发敏感头。如果子域不是同一信任边界,应在 CheckRedirect 中主动删除。

删除 Cookie Header 就能清掉 Cookie 吗?

不一定。配置 Cookie Jar 后,Jar 可能根据响应重新装配匹配域名的 Cookie;需要同时限制允许的目标 origin,必要时不用 Jar 或停止自动重定向。

CheckRedirect 返回普通 error 后响应体谁关闭?

客户端文档规定策略错误返回的上一响应体已关闭;如果返回 ErrUseLastResponse,最后响应体保持打开,必须由调用方关闭。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
PHP Generator用 yield from 组合迭代器的实现方法PHP Generator用 yield from 组合迭代器的实现方法
上一篇
PHP Generator用 yield from 组合迭代器的实现方法
Java record在紧凑构造器中校验组件的实现方法
下一篇
Java record在紧凑构造器中校验组件的实现方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    43次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    138次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    75次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    39次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    26次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码