Rules & Priority
HTTP 路由器负责将传入请求交给能够处理它们的服务。Traefik 允许定义匹配规则并设置路由的优先级。
规则¶
规则是一组配置了取值的匹配器,用于判断特定请求是否满足指定条件。 规则成立时,路由器激活、调用中间件,然后将请求转发到服务。
- 设置规则取值时,请使用反引号
`或转义双引号\"。- 不接受单引号
',因为取值采用 Go 字符串字面量。
- 不接受单引号
- 接受正则表达式(
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 的请求。