跳到正文
Træfɪk

Rules & Priority

HTTP 路由器负责将传入请求交给能够处理它们的服务。Traefik 允许定义匹配规则并设置路由的优先级。

规则

规则是一组配置了取值的匹配器,用于判断特定请求是否满足指定条件。 规则成立时,路由器激活、调用中间件,然后将请求转发到服务。

  • 设置规则取值时,请使用反引号 ` 或转义双引号 \"。
  • 接受正则表达式(regexp)的匹配器使用 Go 风格语法。
  • 可以使用常见的 AND(&&)和 OR(||)逻辑运算符,并遵循通常的优先级规则,也可以使用括号表达复杂规则。
  • NOT(!)运算符支持对匹配器取反。

下表列出所有可用的匹配器:

匹配器 说明
Header(`key`, `value`) 匹配包含名为 key 且值为 value 的请求头的请求。
HeaderRegexp(`key`, `regexp`) 匹配包含名为 key 且值匹配 regexp 的请求头的请求。
Host(`domain`) 匹配主机为 domain 的请求。支持通配符子域名匹配(如 *.example.com)。
HostRegexp(`regexp`) 匹配主机符合 regexp 的请求。
Method(`method`) 匹配方法为 method 的请求。
Path(`path`) 匹配路径为 path 的请求。
PathPrefix(`prefix`) 匹配路径前缀为 prefix 的请求。
PathRegexp(`regexp`) 使用 regexp 匹配请求路径。
Query(`key`, `value`) 匹配名为 key 且值为 value 的查询参数的请求。
QueryRegexp(`key`, `regexp`) 匹配名为 key 且值符合 regexp 的查询参数的请求。
ClientIP(`ip`) 使用 ip 匹配请求客户端 IP。接受 IPv4、IPv6 和 CIDR 格式。

Header 和 HeaderRegexp

Header 和 HeaderRegexp 匹配器支持匹配包含特定请求头的请求。

行为 规则
匹配 Content-Type 请求头为 application/yaml 的请求。 Header(`Content-Type`, `application/yaml`)
匹配 Content-Type 请求头为 application/json 或 application/yaml 的请求。 HeaderRegexp(`Content-Type`, `^application/(json|yaml)$`)
不区分大小写地匹配请求头。 HeaderRegexp(`Content-Type`, `(?i)^application/(json|yaml)$`)

Host 和 HostRegexp

Host 和 HostRegexp 匹配器支持匹配发往指定主机的请求。

这些匹配器不支持非 ASCII 字符;要匹配此类域名,请使用 punycode 编码的值(rfc 3492)。

如果请求 URL 中没有设置 Host(例如 URL 使用 IP 地址),这些匹配器会检查 Host 请求头。

这些匹配器会以小写形式匹配请求的主机。

通配符子域名匹配

Host 匹配器支持单层通配符前缀(*.example.com),用于匹配 example.com 的任意直接子域名。 应优先于 HostRegexp 使用它,因为它支持附加 TLS 选项,并且效率更高。

通配符恰好匹配一个子域标签:*.example.com 可以匹配 foo.example.com,但不能匹配 foo.bar.example.com 或 example.com 本身。

这仅适用于 v3 规则语法(默认语法)。

例外:单独的通配符匹配每个请求

上述规则有一个例外:单独的 * 不作为子域名通配符,而是作为全匹配: Host(`*`) 会匹配每个请求,无论其主机是什么,包括完全没有主机的请求。 这与 TCP HostSNI(`*`) 匹配器的行为一致,使两者保持统一。

行为 规则
匹配 Host 为 example.com 的请求。 Host(`example.com`)
匹配每个请求,无论其主机是什么(见上面的例外)。 Host(`*`)
匹配发往 example.com 任意子域名的请求。 HostRegexp(`^.+\.example\.com$`)
匹配 Host 为 example.com 或 example.org 的请求。 HostRegexp(`^example\.(com|org)$`)
不区分大小写地匹配 Host。 HostRegexp(`(?i)^example\.(com|org)$`)

Method(方法)

Method 匹配器支持根据 HTTP 方法(也称为请求动词)匹配发送的请求。

行为 规则
匹配 OPTIONS 请求。 Method(`OPTIONS`)

Path、PathPrefix 和 PathRegexp

这些匹配器支持根据 URL 路径匹配请求。

精确匹配请使用 Path,前缀匹配请使用 PathPrefix,正则表达式匹配请使用 PathRegexp。

路径始终以 / 开头,PathRegexp 除外。

行为 规则
匹配 /products,但不匹配 /products/shoes 或 /products/。 Path(`/products`)
匹配 /products 及所有以 /products 开头的路径,如 /products/shoes、/products/,也包括 /products-for-sale。 PathPrefix(`/products`)
匹配带有 ID 的 /products/shoes 和 /products/socks 路径,如 /products/shoes/31。 PathRegexp(`^/products/(shoes|socks)/[0-9]+$`)
匹配路径以 .jpeg、.jpg 或 .png 结尾的请求。 PathRegexp(`\.(jpeg|jpg|png)$`)
不区分大小写地匹配 /products 及所有以 /products 开头的路径,如 /products/shoes、/products/,也包括 /products-for-sale。 PathRegexp(`(?i)^/products`)

Query 和 QueryRegexp

Query 和 QueryRegexp 匹配器支持根据查询参数匹配请求。

行为 规则
匹配 mobile 查询参数为 true 的请求,如 /search?mobile=true。 Query(`mobile`, `true`)
匹配查询参数 mobile 没有值的请求,如 /search?mobile。 Query(`mobile`)
匹配 mobile 查询参数为 true 或 yes 的请求。 QueryRegexp(`mobile`, `^(true|yes)$`)
匹配 mobile 查询参数为任意值(包括空值)的请求。 QueryRegexp(`mobile`, `^.*$`)
不区分大小写地匹配查询参数。 QueryRegexp(`mobile`, `(?i)^(true|yes)$`)

ClientIP(客户端 IP)

ClientIP 匹配器支持匹配来自指定客户端 IP 的请求。

它只匹配请求的客户端 IP,不使用 X-Forwarded-For 请求头进行匹配。

行为 规则
匹配来自指定 IP(IPv4)的请求。 ClientIP(`10.76.105.11`)
匹配来自指定 IP(IPv6)的请求。 ClientIP(`::1`)
匹配来自指定子网(IPv4)的请求。 ClientIP(`192.168.1.0/24`)
匹配来自指定子网(IPv6)的请求。 ClientIP(`fe80::/10`)

RuleSyntax(规则语法)

警告

RuleSyntax 选项已弃用,将在下一个主版本中移除。 请勿使用此字段,应将路由器规则改写为 v3 语法。

Traefik v3 引入了新的规则语法(迁移指南)。ruleSyntax 选项支持按路由器配置解析规则时使用的语法。这样可以同时使用不同语法的路由器配置,便于迁移。

ruleSyntax 选项的默认值继承自安装配置(以前称为静态配置)中的 core.defaultRuleSyntax 选项。默认情况下,静态选项 core.defaultRuleSyntax 为 v3,因此默认规则语法也是 v3。

配置示例

以下配置使用文件提供者(结构化)配置 ruleSyntax,允许 Router-v2 使用 v2 语法,而 Router-v3 配置为使用 v3 语法。

## Dynamic configuration
http:
  routers:
    Router-v3:
      rule: HostRegexp(`[a-z]+\\.traefik\\.com`)
      ruleSyntax: v3
    Router-v2:
      rule: HostRegexp(`{subdomain:[a-z]+}.traefik.com`)
      ruleSyntax: v2
## Dynamic configuration
[http.routers]
  [http.routers.Router-v3]
    rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
    ruleSyntax = "v3"
  [http.routers.Router-v2]
    rule = "HostRegexp(`{subdomain:[a-z]+}.traefik.com`)"
    ruleSyntax = "v2"
labels:
  - "traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
  - "traefik.http.routers.Router-v3.ruleSyntax=v3"
  - "traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)"
  - "traefik.http.routers.Router-v2.ruleSyntax=v2"
{
  // ...
  "Tags": [
    "traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
    "traefik.http.routers.Router-v3.ruleSyntax=v3"
    "traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)",
    "traefik.http.routers.Router-v2.ruleSyntax=v2"
  ]
},

优先级计算

默认优先级的计算方式
http:
  routers:
    Router-1:
      rule: "HostRegexp(`[a-z]+\.traefik\.com`)"
      # ...
    Router-2:
      rule: "Host(`foobar.traefik.com`)"
      # ...
[http.routers]
  [http.routers.Router-1]
    rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
    # ...
  [http.routers.Router-2]
    rule = "Host(`foobar.traefik.com`)"
    # ...
labels:
  - "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
  - "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
{
    // ...
    "Tags": [
      "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
      "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
    ]
  }

在此情况下,所有主机为 foobar.traefik.com 的请求都将通过 Router-1 路由,而非 Router-2。

名称 规则 优先级
Router-1 HostRegexp(`[a-z]+\.traefik\.com`) 34
Router-2 Host(`foobar.traefik.com`) 26

上表显示,Router-1 的优先级高于 Router-2。

要解决此问题,必须设置优先级。

为避免路径重叠,路由默认按规则长度降序排列。 优先级直接等于规则长度,因此最长规则具有最高优先级。

优先级值为 0 时会被忽略:priority: 0 表示使用默认的规则长度排序。

支持负优先级值。

Traefik 为内部路由器保留了一个优先级范围,用户自定义路由器的最大优先级值为:

  • 32 位平台为 (MaxInt32 - 1000) = 2147482647,
  • 64 位平台为 (MaxInt64 - 1000) = 9223372036854774807。

提供者优先顺序

来自不同提供者的两条路由具有相同数值优先级时, Traefik 使用安装配置选项 providers.precedence 决定哪条路由优先。 在 precedence 中列在前面的提供者赢得此次平局。

示例

## Dynamic configuration
http:
  routers:
    Router-1:
      rule: "HostRegexp(`[a-z]+\\.traefik\\.com`)"
      entryPoints:
      - "web"
      service: service-1
      priority: 1
    Router-2:
      rule: "Host(`foobar.traefik.com`)"
      entryPoints:
      - "web"
      priority: 2
      service: service-2
## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
    entryPoints = ["web"]
    service = "service-1"
    priority = 1
  [http.routers.Router-2]
    rule = "Host(`foobar.traefik.com`)"
    entryPoints = ["web"]
    priority = 2
    service = "service-2"
labels:
  - "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
  - "traefik.http.routers.Router-1.entryPoints=web"
  - "traefik.http.routers.Router-1.service=service-1"
  - "traefik.http.routers.Router-1.priority=1"
  - "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
  - "traefik.http.routers.Router-2.entryPoints=web"
  - "traefik.http.routers.Router-2.service=service-2"
  - "traefik.http.routers.Router-2.priority=2"
  {
    // ...
    "Tags": [
      "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
      "traefik.http.routers.Router-1.entryPoints=web",
      "traefik.http.routers.Router-1.service=service-1",
      "traefik.http.routers.Router-1.priority=1"
      "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)",
      "traefik.http.routers.Router-2.entryPoints=web",
      "traefik.http.routers.Router-2.service=service-2",
      "traefik.http.routers.Router-2.priority=2"
    ]
  }

在上例中,优先级经过配置后,Router-2 可以处理主机为 foobar.traefik.com 的请求。


版权所有 © 头文件软件工作室

文档由 HeadFile Studio 翻译。

Traefik v3.7 中文快照 · 原文版权归 Traefik Labs 及贡献者所有 · MIT 许可证