Caddyfile 支持
Caddy 模块通过其命名空间在注册时自动添加到原生 JSON 配置中,使其既可用又可文档化。这使得 Caddyfile 支持完全是可选的,但通常被喜欢使用 Caddyfile 的用户所要求。
Unmarshaler
要为你的模块添加 Caddyfile 支持,只需实现 caddyfile.Unmarshaler
接口。你可以通过如何解析标记来选择你的模块所具有的 Caddyfile 语法。
unmarshaler 的工作就是简单地设置你的模块类型,例如通过使用传递给它的 caddyfile.Dispenser
来填充其字段。例如,一个名为 Gizmo
的模块类型可能有这样的方法:
// UnmarshalCaddyfile 实现 caddyfile.Unmarshaler。语法:
//
// gizmo <name> [<option>]
//
func (g *Gizmo) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // 消费指令名称
if !d.Args(&g.Name) {
// 参数不足
return d.ArgErr()
}
if d.NextArg() {
// 可选参数
g.Option = d.Val()
}
if d.NextArg() {
// 参数过多
return d.ArgErr()
}
return nil
}
在方法的 godoc 注释中记录语法是一个好主意。有关解析 Caddyfile 的更多信息,请参阅 caddyfile
包的 godoc。
指令名称标记可以通过简单的 d.Next()
调用来消费/跳过。
确保使用 d.NextArg()
或 d.RemainingArgs()
检查缺失和/或多余的参数。使用 d.ArgErr()
获取简单的"无效情况"消息,或使用 d.Errf("some message")
来创建一个有帮助的错误消息,解释问题(最好还提供建议的解决方案)。
你还应该添加一个接口守卫以确保接口被正确满足:
var _ caddyfile.Unmarshaler = (*Gizmo)(nil)
块
要接受比单行更多的配置,你可能希望允许带有子指令的块。这可以使用 d.NextBlock()
并迭代直到返回到原始嵌套级别:
for nesting := d.Nesting(); d.NextBlock(nesting); {
switch d.Val() {
case "sub_directive_1":
// ...
case "sub_directive_2":
// ...
}
}
只要循环的每次迭代都消费整个段(行或块),这就是处理块的一种优雅方式。
HTTP 指令
HTTP Caddyfile 是 Caddy 的默认 Caddyfile 适配器语法(或"服务器类型")。它是可扩展的,意味着你可以为你的模块注册自己的"顶级"指令:
func init() {
httpcaddyfile.RegisterDirective("gizmo", parseCaddyfile)
}
如果你的指令只返回单个 HTTP 处理程序(这很常见),你可能会发现 RegisterHandlerDirective
更容易:
func init() {
httpcaddyfile.RegisterHandlerDirective("gizmo", parseCaddyfileHandler)
}
基本思想是,你与指令关联的解析函数返回一个或多个 ConfigValue
值。(或者,如果使用 RegisterHandlerDirective
,它直接返回填充的 caddyhttp.MiddlewareHandler
值。)每个配置值都与一个"类"相关联,这有助于 HTTP Caddyfile 适配器知道它可以在最终 JSON 配置的哪些部分中使用。所有配置值都被转储到一个堆中,适配器在构建最终 JSON 配置时从中提取。
这种设计允许你的指令为任何已识别的类返回任何配置值,这意味着它可以影响 HTTP Caddyfile 适配器为其指定了类的配置的任何部分。
如果你已经实现了 UnmarshalCaddyfile()
方法,那么你的解析函数可能就像这样简单:
// parseCaddyfileHandler 将 h 中的标记解组为新的中间件处理程序值。
func parseCaddyfileHandler(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var g Gizmo
err := g.UnmarshalCaddyfile(h.Dispenser)
return g, err
}
有关如何使用 httpcaddyfile.Helper
类型的更多信息,请参阅 httpcaddyfile
包 godoc。
处理程序顺序
所有返回 HTTP 中间件/处理程序值的指令都需要按正确的顺序进行评估。例如,设置站点根目录的处理程序必须在访问根目录的处理程序之前,这样它才能知道目录路径是什么。
HTTP Caddyfile 为标准指令有一个硬编码的排序。这确保用户不需要知道其 Web 服务器最常见功能的实现细节,并使编写正确配置变得更容易。单一的硬编码列表也防止了由于 Caddyfile 的可扩展性质而导致的不确定性。
当你注册一个新的处理程序指令时,它必须被添加到该列表中才能使用(在 route
块之外)。 这可以通过以下三种方法之一完成:
-
(推荐)插件作者可以在
init()
中调用httpcaddyfile.RegisterDirectiveOrder
,在注册指令后,将指令插入到相对于另一个标准指令的顺序中。这样做,用户可以直接在他们的站点中使用指令,无需额外设置。例如,要将你的指令gizmo
插入到header
处理程序之后进行评估:httpcaddyfile.RegisterDirectiveOrder("gizmo", httpcaddyfile.After, "header")
-
用户可以添加
order
全局选项 来修改其 Caddyfile 的标准顺序。例如:order gizmo before respond
将插入一个新的指令gizmo
在respond
处理程序之前进行评估。然后可以正常使用该指令。 -
用户可以将指令放在
route
块 中。因为路由块中的指令不会被重新排序,所以在路由块中使用的指令不需要出现在列表中。
如果你选择后两个选项之一,请为你的用户记录一个建议,说明在列表中的哪个位置是正确放置你的指令的位置,以便他们可以正确使用它。
类
此表描述了 HTTP Caddyfile 适配器识别的每个具有导出类型的类:
类名 | 预期类型 | 描述 |
---|---|---|
bind | []string |
服务器监听器绑定地址 |
route | caddyhttp.Route |
HTTP 处理程序路由 |
error_route | *caddyhttp.Subroute |
HTTP 错误处理路由 |
tls.connection_policy | *caddytls.ConnectionPolicy |
TLS 连接策略 |
tls.cert_issuer | certmagic.Issuer |
TLS 证书颁发者 |
tls.cert_loader | caddytls.CertificateLoader |
TLS 证书加载器 |
服务器类型
从结构上讲,Caddyfile 是一种简单的格式,因此可以有不同的 Caddyfile 格式(有时称为"服务器类型")来满足不同的需求。
默认的 Caddyfile 格式是 HTTP Caddyfile,你可能已经很熟悉了。这种格式主要配置 http
应用,同时可能只在 Caddy 配置结构的其他部分(例如 tls
应用以加载和自动化证书)中撒一些配置。
要配置 HTTP 以外的应用,你可能想要实现自己的配置适配器,使用你自己的服务器类型。Caddyfile 适配器实际上会为你解析输入并给你服务器块和选项的列表,然后由你的适配器来理解该结构并将其转换为 JSON 配置。