首页
/ Traefik Headers 中间件完全指南:自定义请求/响应头、CORS 与安全响应头实战

Traefik Headers 中间件完全指南:自定义请求/响应头、CORS 与安全响应头实战

2026-09-07 17:30:31作者:段琳惟

本文基于当前仓库 docs/content/reference/routing-configuration/http/middlewares/headers.md 文档,结合 Traefik v3 源码(pkg/middlewares/headers/pkg/config/dynamic/)展开。核心主题是 HTTP Headers 中间件:它在请求被转发到后端之前修改请求头,并在响应返回客户端之前修改响应头,可用于注入自定义头、配置 CORS 策略、下发 HSTS 等安全头。读完本文,你将掌握 Headers 中间件在 YAML / TOML / Docker Labels / Swarm Tags / Kubernetes CRD 五种载体下的完整配置方法,理解其内部的 Secure(安全头)、Custom(自定义头)、CORS 三层处理模型,并能区分“同名字段覆盖旧值”的语义。

Headers 中间件在 Traefik 动态配置中的位置

Headers 属于 HTTP 层中间件,与 AddPrefix、BasicAuth、RateLimit 等一样,在动态配置(Dynamic Configuration)中通过 http.middlewares.<name>.headers 声明。中间件本身不产生路由规则,而是挂在 Router(路由器)上,在请求命中某条路由之后、转发给后端 Service 之前按顺序执行。

Traefik 默认代理转发时会自动带上若干与客户端、宿主、协议相关的 X-Forwarded-* 头(详见下文)。而 Headers 中间件处理的则是显式配置的头:

Property HTTP Header 说明
Client's IP X-Forwarded-ForX-Real-Ip 客户端真实 IP
Host X-Forwarded-Host 原始请求的 Host
Port X-Forwarded-Port 原始请求端口
Protocol X-Forwarded-Proto 原始请求协议(http/https)
Proxy Server's Hostname X-Forwarded-Server 代理服务器主机名

这些头由 Traefik 在代理转发时自动加入,即使不配置 Headers 中间件也存在;Headers 中间件的主要价值在于按你的业务需要增删、覆盖或改写它们以及其它任意头。

基础示例一:同时为请求与响应添加自定义头

以下配置给被转发的请求添加 X-Script-Name: test,并给响应添加 X-Custom-Response-Header: value。五种配置载体写法等价:

http:
  middlewares:
    testHeader:
      headers:
        customRequestHeaders:
          X-Script-Name: "test"
        customResponseHeaders:
          X-Custom-Response-Header: "value"
[http.middlewares]
  [http.middlewares.testHeader.headers]
    [http.middlewares.testHeader.headers.customRequestHeaders]
        X-Script-Name = "test"
    [http.middlewares.testHeader.headers.customResponseHeaders]
        X-Custom-Response-Header = "value"
labels:
  - "traefik.http.middlewares.testHeader.headers.customrequestheaders.X-Script-Name=test"
  - "traefik.http.middlewares.testHeader.headers.customresponseheaders.X-Custom-Response-Header=value"
{
  //...
  "Tags": [
    "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test",
    "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value"
  ]
}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-header
spec:
  headers:
    customRequestHeaders:
      X-Script-Name: "test"
    customResponseHeaders:
      X-Custom-Response-Header: "value"

注意:customRequestHeaderscustomResponseHeadersmap[string]string 类型(参见 pkg/config/dynamic/middlewares.go)。在 Labels / Tags 载体中,map 的每个 key 都会展开成一条独立的 key=value 项,且 map 键大小写不敏感——文档与示例中 testHeadertestheader 混用正是因为中间件名会被统一规范化处理。

基础示例二:添加与删除头(空值即删除)

Headers 中间件遵循一个关键约定:将某个头的值设为空字符串 "",等于删除该头。下面的配置同时演示了三种操作——为请求添加 X-Script-Name、从请求中剥离 X-Custom-Request-Header、从响应中剥离 X-Custom-Response-Header

http:
  middlewares:
    testHeader:
      headers:
        customRequestHeaders:
          X-Script-Name: "test"           # 添加
          X-Custom-Request-Header: ""     # 删除
        customResponseHeaders:
          X-Custom-Response-Header: ""    # 删除
[http.middlewares]
  [http.middlewares.testHeader.headers]
    [http.middlewares.testHeader.headers.customRequestHeaders]
        X-Script-Name = "test"            # 添加
        X-Custom-Request-Header = ""      # 删除
    [http.middlewares.testHeader.headers.customResponseHeaders]
        X-Custom-Response-Header = ""     # 删除
labels:
  - "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
  - "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header="
  - "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
{
  "Tags" : [
    "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test",
    "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header=",
    "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
  ]
}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-header
spec:
  headers:
    customRequestHeaders:
      X-Script-Name: "test"               # 添加
      X-Custom-Request-Header: ""         # 删除
    customResponseHeaders:
      X-Custom-Response-Header: ""        # 删除

这一“空值即删除”语义有清晰的分支实现依据:在 pkg/middlewares/headers/header.gomodifyCustomRequestHeaders 中,value == "" 时调用 req.Header.Del(header)(对 X-Forwarded-For 有特殊处理,见下文);而响应侧,PostRequestModifyResponseHeaders 对空值调用 res.Header.Del(header),非空则 res.Header.Set(header, value)。同名的响应头删除逻辑适用于后端返回的任意响应头。

修改 Host 与 X-Forwarded-For 的源码级细节

在请求头修改逻辑中(pkg/middlewares/headers/header.go),有两个值得注意的特殊分支,它们来自 Go 标准库 net/http 的特定行为:

  1. HostHost 是 HTTP/1.1 中不进入 Header map 的特殊字段。因此当 key 为 Host(大小写不敏感比较,strings.EqualFold)时,代码直接赋值 req.Host = value,而不是 req.Header.Set(...)。即 customRequestHeaders: {Host: "api.example.com"} 可以改写转发目标的主机头。
  2. X-Forwarded-For 置空:当 key 是 X-Forwarded-For 且值为空时,代码执行 req.Header[header] = nil 而非 Del,这是为了规避 Go 标准库一个已知提交(golang/go 中关于反向代理 X-Forwarded-For 合并行为的改动)导致的特殊路径,确保在彻底移除该头时不会让 httputil/oxy 的转发逻辑把它“重新拼接”出来。

安全响应头:HSTS、点击劫持防护等

安全相关头(HSTS、浏览器 XSS 过滤等)与自定义头的配置方式完全一致,只需把对应布尔开关或字符串值设为 true / 具体值即可。例如同时启用“禁止 iframe 嵌入”与“浏览器 XSS 过滤”:

http:
  middlewares:
    testHeader:
      headers:
        frameDeny: true
        browserXssFilter: true
[http.middlewares]
  [http.middlewares.testHeader.headers]
    frameDeny = true
    browserXssFilter = true
labels:
  - "traefik.http.middlewares.testHeader.headers.framedeny=true"
  - "traefik.http.middlewares.testHeader.headers.browserxssfilter=true"
{
  "Tags" : [
    "traefik.http.middlewares.testheader.headers.framedeny=true",
    "traefik.http.middlewares.testheader.headers.browserxssfilter=true"
  ]
}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-header
spec:
  headers:
    frameDeny: true
    browserXssFilter: true

安全头内部的执行模型

在实现上,安全头由独立的 Secure 处理层负责。看 pkg/middlewares/headers/secure.go,Traefik 将 Headers 配置中所有安全相关字段逐一映射进 unrolled/secure 库的 secure.Options,随后构建 secure.New(opt) 实例。响应头写入发生在请求转发完成之后:secureHeader.ServeHTTP 先让 unrolled/secure 对请求做校验与改写(通过 HandlerFuncWithNextForRequestOnly),再经由 secure.ModifyResponseHeaders 在响应阶段补上各类安全头。

安全头在开发环境可能需要“放开”:isDevelopment: true 时会缓解 allowedHosts、SSL、STS 等选项带来的副作用(本地调试常用 HTTP + localhost,而非生产域名)。配置结构体注释与默认值可对照 pkg/config/dynamic/middlewares.go

CORS 头与预检请求的直答处理

CORS(跨源资源共享)头可以像自定义头一样配置。一个关键行为差异:一旦配置了 CORS 头,中间件不会把预检(preflight)请求转发给后端服务,而是直接生成并返回响应。下面是完整示例:

http:
  middlewares:
    testHeader:
      headers:
        accessControlAllowMethods:
          - GET
          - OPTIONS
          - PUT
        accessControlAllowHeaders:
          - "*"
        accessControlAllowOriginList:
          - https://foo.bar.org
          - https://example.org
        accessControlMaxAge: 100
        addVaryHeader: true
[http.middlewares]
  [http.middlewares.testHeader.headers]
    accessControlAllowMethods = ["GET", "OPTIONS", "PUT"]
    accessControlAllowHeaders = [ "*" ]
    accessControlAllowOriginList = ["https://foo.bar.org","https://example.org"]
    accessControlMaxAge = 100
    addVaryHeader = true
labels:
  - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
  - "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*"
  - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"
  - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
  - "traefik.http.middlewares.testheader.headers.addvaryheader=true"
{
  "Tags" : [
    "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT",
    "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*",
    "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org",
    "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100",
    "traefik.http.middlewares.testheader.headers.addvaryheader=true"
  ]
}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-header
spec:
  headers:
    accessControlAllowMethods:
      - "GET"
      - "OPTIONS"
      - "PUT"
    accessControlAllowHeaders:
      - "*"
    accessControlAllowOriginList:
      - "https://foo.bar.org"
      - "https://example.org"
    accessControlMaxAge: 100
    addVaryHeader: true

预检请求的判定与响应生成

判定逻辑见 processCorsHeaders:当请求同时满足以下三个条件时被识别为 CORS 预检请求——方法为 OPTIONS、带有 Origin 头、带有 Access-Control-Request-Method 头。此时中间件直接拼装响应头并返回 200 OK(并置 Content-Length: 0),不再调用后端(见 ServeHTTP)。

响应阶段(PostRequestModifyResponseHeaders)还会处理普通跨源请求:若请求的 Origin 命中允许列表,则回写 Access-Control-Allow-Origin;若配置 accessControlAllowCredentials 则回写 Access-Control-Allow-Credentials: true;配置了 accessControlExposeHeaders 时回写允许暴露的头;最后按 addVaryHeader 决定是否追加 Vary: Origin(已存在 Vary: Origin 时不重复添加)。

文档特别提醒:示例中的 CORS 配置并非权威或穷尽列举,不应直接照搬到生产环境,生产使用前请结合自身安全策略与 CORS 规范校验。

通配符与凭据的交互规则

matchOriginpkg/middlewares/headers/header.go)可以看到通配符 * 的精细处理:命中 * 时,若同时启用了 accessControlAllowCredentials,由于浏览器不允许带凭据的请求使用 * 通配,Traefik 会把实际请求的 Origin 值回写为 Access-Control-Allow-Origin;未启用凭据时才直接回写 *。同理,预检响应中若 Access-Control-Allow-Headers / Access-Control-Allow-Methods 配置了 * 且启用了凭据,会改为回显客户端发送的 Access-Control-Request-Headers / 实际请求方法(参见 pkg/middlewares/headers/header.go)。

全部配置选项参考

通用约束(重要):

  • 若自定义头的名称与已存在的头相同,会直接覆盖(overwrite)原值。
  • 安全相关头的详细语义遵循上游 unrolled/secure 库的可选配置项。
  • 除下方主表外,Traefik 对几个“组合型”配置(accessControlAllowOriginListaccessControlAllowOriginListRegex)有额外专节说明,见本文后半部分。
Field Description Default Required
customRequestHeaders 请求侧自定义头列表(name → value)。 [] No
customResponseHeaders 响应侧自定义头列表(name → value)。 [] No
accessControlAllowCredentials 是否允许请求携带用户凭据。 false No
accessControlAllowHeaders 允许的请求头名称列表(用于预检响应)。 [] No
accessControlAllowMethods 允许的请求方法列表(用于预检响应)。 [] No
accessControlAllowOriginList 允许的 Origin 列表(支持 * 通配),详见下文 accessControlAllowOriginList [] No
accessControlAllowOriginListRegex 用正则匹配允许的 Origin,详见下文 accessControlAllowOriginListRegex [] No
accessControlExposeHeaders 允许暴露给浏览器 JS 的响应头(对应 Access-Control-Expose-Headers)。 [] No
accessControlMaxAge 预检请求结果可被缓存的时长(秒)。 0 No
addVaryHeader accessControlAllowOriginList 配合使用:是否自动添加/修改 Vary 头,以声明服务端响应可能因 Origin 值不同而变化。 false No
allowedHosts 允许的域名列表(白名单校验 Host)。 [] No
hostsProxyHeaders 携带被代理主机名的请求头 key 列表。 [] No
sslProxyHeaders 一组用于判定“请求已通过 HTTPS”的请求头键值对(例如 "X-Forwarded-Proto": "https"),适用于前面还有其他代理的场景。 {} No
stsSeconds Strict-Transport-Security 头的 max-age(秒)。 - No
stsIncludeSubdomains 为 true 时,STS 头追加 includeSubDomains 指令。 false No
stsPreload 为 STS 头追加 preload 标记。 false No
forceSTSHeader 为 true 时,即使 HTTP 连接也添加 STS 头。 false No
frameDeny 为 true 时添加 X-Frame-Options: DENY(禁止页面被 iframe 嵌入)。 false No
customFrameOptionsValue 自定义 X-Frame-Options 值;设置了该项会覆盖 frameDeny "" No
contentTypeNosniff 为 true 时添加 X-Content-Type-Options: nosniff(禁止 MIME 类型嗅探)。 false No
browserXssFilter 为 true 时添加 X-XSS-Protection: 1; mode=block false No
customBrowserXSSValue 自定义 X-XSS-Protection 值;设置了该项会覆盖 browserXssFilter "" No
contentSecurityPolicy 自定义 Content-Security-Policy 头的值。 "" No
contentSecurityPolicyReportOnly 自定义 Content-Security-Policy-Report-Only 头的值。 "" No
publicKey 实现 HPKP 公钥固定(用于防御证书伪造类中间人攻击)。 "" No
referrerPolicy 控制浏览器对 Referer 头的转发策略(Referrer-Policy 头)。 "" No
permissionsPolicy 允许站点控制浏览器特性(Permissions-Policy 头)。 "" No
isDevelopment 开发环境开关:为 true 时缓解 allowedHosts、SSL 与 STS 选项在本地调试中的副作用。 false No

结构体层面的字段类型、kubebuilder 校验与废弃标记可继续查阅 pkg/config/dynamic/middlewares.go,其中 FeaturePolicy(改用 PermissionsPolicy)、SSLRedirect / SSLTemporaryRedirect(改用 EntryPoint 重定向或 RedirectScheme)、SSLHost / SSLForceHost(改用 RedirectRegex)均已被标记为废弃。

accessControlAllowOriginList

accessControlAllowOriginList 通过为不同来源返回不同取值来声明“资源是否可以跨源共享”,它是一个允许的 Origin 列表:

  • 可配置通配符 *,匹配所有请求;若后端服务自行写入了该头的值,会被 Traefik 覆盖。
  • 不再支持 null:因为 Access-Control-Allow-Origin: null 已不再被规范推荐作为返回值。

accessControlAllowOriginListRegex

accessControlAllowOriginListRegexaccessControlAllowOriginList 的“正则版”对应项:允许所有能匹配到列表中任一正则表达式的 Origin。

两个实用提示:

  • 正则与替换可用在线 Go 正则工具或 Regex101 等预先验证。
  • YAML 中转义陷阱:YAML 内定义正则时,所有需要转义的字符都要双写,例如 example\.com 必须写成 example\\.com

正则的编译发生在中间件构建期:从 pkg/middlewares/headers/header.go 可以看到,NewHeader 会对 AccessControlAllowOriginListRegex 逐条执行 regexp.Compile,一旦有非法正则,会直接返回形如 error occurred during origin parsing: ... 的构建错误;编译成功的正则保存在 allowOriginRegexes 中,供请求匹配使用(matchOrigin)。

从源码看三层处理链与配置合法性

Newpkg/middlewares/headers/headers.go)是整个中间件的组装入口,它按“是否有某类配置”依次决定启用哪些层,最终形成 SecureMiddleware → HeaderMiddleware(自定义头 / CORS)→ next 的处理链:

  1. 用三个检测函数对配置归类:HasSecureHeadersDefined()HasCustomHeadersDefined()HasCorsHeadersDefined()(三者定义见 pkg/config/dynamic/middlewares.go);
  2. 若三者全部为 false(即中间件没有任何有效配置),构建直接失败,返回错误 "headers configuration not valid"——对应单元测试 TestNew_withoutOptions 对空配置断言报错的行为;
  3. 有安全头配置则先挂 unrolled/secure 层,有自定义头或 CORS 配置则再包一层 NewHeader
  4. STSSeconds 指针为 0 时配置依然有效(测试 TestNew_withSTSSecondsZero 验证了这一点),此时按结构体注释语义“不输出 STS 头”。

allowedHosts 的行为可通过测试佐证:TestNew_allowedHosts 显示,Host 命中白名单时放行(200),Host 缺失或不在名单中时被拒绝。此外 Test1xxResponses 验证了中间件对 103 Early Hints 等 1xx 中间响应也能正确保留与追加自定义响应头,说明其响应改写是基于可捕获 1xx 的响应修改器(NewResponseModifier)完成的。

适用载体与引用方式小结

Headers 中间件的配置可来自 Traefik 的全部动态配置来源,本文示例覆盖了其中四类最常用载体:

  • 文件(File)http.middlewares 下的 YAML / TOML 动态配置段;
  • Docker / Swarm:容器 Labels 与服务 Tags,键格式统一为 traefik.http.middlewares.<name>.headers.<字段>
  • Kubernetestraefik.io/v1alpha1Middleware CRD,通过 metadata.name 引用;
  • 在 Router 上通过 middlewares: [testheader] 形式引用(K8s 则通过 IngressRoutemiddlewares 列表引用)。

若你正在将 Traefik 用于企业级业务场景,可进一步阅读仓库中的 Traefik for Business Applications 补充说明;Headers 中间件作为其中基础的 HTTP 安全加固手段,通常与认证、限流等中间件一起编排在路由链上。

常见实战建议

  • 用空值删除头是双向的:请求头与响应头都能删,常用于“剔除后端/上游带来的敏感头”或“清理默认的 X-Powered-By 等指纹信息”。
  • 统一收敛反代头:当 Traefik 前面还有其它代理(如云 LB、Nginx)时,用 sslProxyHeaders: {"X-Forwarded-Proto": "https"} 让 Traefik 正确感知 HTTPS,避免把安全判断建立在错误的协议上。
  • HSTS 与 HTTPforceSTSHeader 默认 false,意味着纯 HTTP 连接不会下发 STS 头;若整体站点强制 HTTPS,可打开它,但需确保混合内容场景不会被误伤。
  • CORS 与 Vary:当允许列表含多个来源且你使用了 CDN/浏览器缓存时,务必开启 addVaryHeader,避免不同 Origin 的响应被缓存复用。
  • Kubernetes 命名:CRD 的 metadata.name 需符合 K8s 命名规范,与 testHeader 这类 camelCase 用法略有差异,示例中使用了 test-header
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
858
1.35 K
docsdocs
暂无描述
Markdown
899
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
923
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.83 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
532
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
524
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
393