route
按字面意思将一组指令作为单个单元进行评估。
route 块中包含的指令不会在内部重新排序。只有 HTTP 处理器指令(添加处理器或中间件到链中的指令)可以在 route 块中使用。
这个指令是一个特例,因为它的子指令也是常规指令。
语法
route [<匹配器>] {
<指令...>
}
- <指令...> 是指令或指令块的列表,每行一个,就像 route 块外一样;但这些指令不会被重新排序。只能使用 HTTP 处理器指令。
用途
route
指令在某些高级用例或边缘情况下很有帮助,可以完全控制 HTTP 处理器链的某些部分。
由于 HTTP 中间件评估的顺序很重要,Caddyfile 通常会在解析后重新排序指令,使 Caddyfile 更容易使用;您不必担心输入内容的顺序。
虽然内置顺序与大多数站点兼容,但有时您需要手动控制顺序,可能是整个站点或仅仅是其中的一部分。这就是 route
指令的用途。
为了说明这一点,考虑两个终止处理器的情况:redir
和 file_server
。它们都向客户端写入响应,并且不会调用链中的下一个处理器,因此对于特定请求只会执行其中一个。那么哪个应该先执行?通常,redir
在 file_server
之前执行,因为通常您希望只在特定情况下发出重定向,而在一般情况下提供文件服务。
然而,有时第二个指令(redir
)可能比第二个(file_server
)有更具体的匹配器。换句话说,您希望在一般情况下重定向,而只在特定情况下提供文件服务。
因此,您可能会尝试这样的 Caddyfile(但这不会按预期工作!):
example.com {
file_server /specific.html
redir https://anothersite.com{uri}
}
问题在于指令排序后,redir
会在 file_server
之前。
但在这种情况下,redir
的匹配器(隐式的 *
)是 file_server
匹配器的超集(*
是 /specific.html
的超集)。
幸运的是,解决方案很简单:只需将这两个指令包装在一个 route
块中,以确保 file_server
在 redir
之前执行:
example.com {
route {
file_server /specific.html
redir https://anothersite.com{uri}
}
}
现在 file_server
将在 redir
之前被链接,因为顺序是按字面意思解释的。
相似指令
有其他指令也可以包装 HTTP 处理器指令,但根据您想要表达的行为,每个都有其用途:
-
handle
像route
一样包装其他指令,但有两个区别:1) handle 块之间是互斥的,2) handle 内的指令会正常重新排序。 -
handle_path
与handle
相同,但在运行其处理器之前会从请求中去除前缀。 -
handle_errors
类似于handle
,但仅在 Caddy 在请求处理过程中遇到错误时才调用。
示例
按原样代理到 /api
的请求,并根据请求是否匹配磁盘上的文件重写所有其他请求,否则重写到 /index.html
。然后提供该文件服务。
由于 try_files
的指令顺序高于 reverse_proxy
,因此通常它会被排序在前面并先运行;这会导致 API 请求全部被重写为 /index.html
并且无法匹配 /api*
,因此它们都不会被代理,而是会从 file_server
得到一个 404
。将所有内容包装在一个 route
中确保 reverse_proxy
总是先运行,在请求被重写之前。
example.com {
root * /srv
route {
reverse_proxy /api* localhost:9000
try_files {path} /index.html
file_server
}
}