文档
一个 项目

route

将一组指令按字面逐一评估并作为单个单元处理。

位于 route 块内的指令不会被在内部重新排序route 块中只能使用 HTTP 处理器指令(即将处理器或中间件添加到链中的指令)。

这个指令是一个特殊情况,因为它的子指令同时也是常规指令。

语法

route [<matcher>] {
	<directives...>
}
  • <directives...> 是一个指令或指令块的列表,每行一个,就像在 route 块外一样;不同的是这些指令不会被重新排序。只能使用 HTTP 处理器指令。

用途

route 指令在某些高级用例或边缘情况下很有用,可让你对 HTTP 处理器链的某些部分进行绝对控制。

由于 HTTP 中间件评估的顺序很重要,Caddyfile 在解析后通常会对指令进行重新排序,以使 Caddyfile 更易于使用;这样你就无需担心输入指令的顺序。

尽管 内置顺序 与大多数站点兼容,但有时你需要手动控制顺序,无论是针对整个站点还是仅针对其中一部分。这正是 route 指令的用途所在。

举例来说,考虑两个终结性处理器的情况:redirfile_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_serverredir 之前执行:

example.com {
	route {
		file_server /specific.html
		redir https://anothersite.com{uri}
	}
}

现在 file_server 会在 redir 之前被串入链中,因为顺序按字面意义保留。

类似指令

还有其他可以包装 HTTP 处理器指令的指令,但每个指令的用途取决于你想表达的行为:

  • handleroute 一样包装其他指令,但有两个区别:1)handle 块彼此之间是互斥的;2)handle 内部的指令会按常规被重新排序

  • handle_path 的行为与 handle 相同,但在运行其处理器之前会从请求中去除一个前缀。

  • handle_errors 类似于 handle,但只在 Caddy 在请求处理期间遇到错误时被调用。

示例

将对 /api 的请求按原样代理,其它所有请求则根据是否在磁盘上匹配到文件来重写,否则重写为 /index.html,然后提供该文件。

由于 try_files 的指令顺序高于 reverse_proxy,因此通常在排序后会先运行 try_files;这会导致所有 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
	}
}