Caddy 2 HTTP handlers come in two flavors: middleware and responders.
- Middleware are in the middle of a request chain; i.e. they have a
next
handler to invoke. - Responders are content origins, at the end of a request chain; i.e. there is no
next
handler. Any handlers defined after it would not be invoked.
Caveat: Sometimes a handler's role is ambiguous. For example, a caching handler would be middleware on a cache miss (it needs to invoke the upstream handlers for a response, then cache it), but on a cache hit it would be a responder, since no further handlers would be invoked (it would simply write the response).
With either option, the general rule or idea is that handlers are executed from top-to-bottom, with the responder being last, and the return value (response or error) propagates back up to the top.
- Pros: All handlers in one, linear list. This allows handlers with ambiguous roles like a cache handler to be defined the same as all others; less nesting.
- Cons: Not always obvious which handler provides the response; for example, adding handlers after
file_server
would be a logical error because the file server will never invoke a later middleware.
"handle": [
{
"handler": "cache"
},
{
"handler": "encode",
"encodings": {"gzip": {}, "zstd": {}}
},
{
"handler": "templates"
},
{
"handler": "file_server",
"root": "/www/example.com"
}
]
- Pros: Responder is separated out from the middleware, so it's obvious where the content comes from. Since there is only a single responder, it's impossible to put it in the middle of a handler chain by accident.
- Cons: Not obvious where handlers with ambiguous role go: does a cache handler go in middleware or responder? Truth is, it depends on the request; sometimes it is a middleware (cache miss), other times it is a responder (cache hit). So it would be configured as a responder, then on cache miss would invoke a nested set of handlers. This approach leads to more nesting in the config. That can be confusing, but also clearer in some ways.
"respond": {
"responder": "cache",
"if_cache_miss": [
{
"apply": [
{
"middleware": "encode",
"encodings": {"gzip": {}, "zstd": {}}
},
{
"middleware": "templates"
}
],
"respond": {
"responder": "file_server",
"root": "/www/example.com"
}
}
]
}
(some of these configs are contrived, but the basic structure is represented)