mirror of
https://github.com/caddyserver/caddy.git
synced 2025-07-09 03:04:57 -04:00
Important notes about subtle things related to the needs of the API
parent
8c9a00ea73
commit
f9e4d58dd5
@ -18,19 +18,25 @@ type MyHandler struct {
|
||||
}
|
||||
```
|
||||
|
||||
It must also implement the middleware.Handler interface. We do this by adding a method called ServeHTTP. Right now, let's just pass the request to the next Handler in the chain:
|
||||
It must also implement the middleware.Handler interface. We do this by adding a method called ServeHTTP and two one-liners called GetNext and SetNext. Right now, let's just pass the request to the next Handler in the chain:
|
||||
|
||||
```go
|
||||
func (h MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
return h.Next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// These allow the middleware stack to be traversed like a singly-linked list
|
||||
func (h *MyHandler) GetNext() middleware.Handler { return h.Next }
|
||||
func (h *MyHandler) SetNext(next middleware.Handler) { h.Next = next }
|
||||
```
|
||||
|
||||
That's all there is to it. Put your middleware logic in the ServeHTTP method, and add any properties that your middleware may need to access to the struct type you defined your middleware to be.
|
||||
|
||||
Be careful to use pointer receivers.
|
||||
|
||||
## Return Values and Writing Responses
|
||||
|
||||
Oh yes, those pesky return values. You read the documentation so you already know what they mean. But what does that imply for the behavior of your middleware?
|
||||
Oh yes, those pesky return values on `ServeHTTP()`. You read the documentation so you already know what they mean. But what does that imply for the behavior of your middleware?
|
||||
|
||||
Some handlers are endpoints: they create a response and write it along with the status code to the client. Effectively, this terminates the chain. You wouldn't want to write a document out to the client and then tell the next handler in the chain, "Okay it's all yours!" In this situation, you would *not* call Next().
|
||||
|
||||
@ -53,18 +59,31 @@ func MyMiddleware(c *Controller) (middleware.Middleware, error) {
|
||||
// do parsing
|
||||
}
|
||||
|
||||
// set up your middleware type
|
||||
myType := mymiddleware.MyType{/* ... */}
|
||||
// Don't create your middleware struct in this function!
|
||||
|
||||
return func(next middleware.Handler) middleware.Handler {
|
||||
// chain in the next handler and return it
|
||||
myType.Next = next
|
||||
return myType
|
||||
// This function will be called every time the server
|
||||
// is started. Create and return your middleware
|
||||
// struct here to ensure it gets the latest config.
|
||||
// Return a POINTER - very important!
|
||||
return &mymiddleware.MyType{
|
||||
Next: next,
|
||||
// ...
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
The Controller gives you access to the server.Config and some really helpful parsing utilities to easily get values out of the Caddyfile.
|
||||
The Controller gives you access to the `*server.Config` and some really helpful parsing utilities to easily get values out of the Caddyfile.
|
||||
|
||||
Your middleware type should be able to support multiple invocations, usually called "rules" - for example, a Caddyfile like this:
|
||||
|
||||
```
|
||||
rewrite /foo /bar
|
||||
rewrite /bar /baz
|
||||
```
|
||||
|
||||
creates just 1 struct but that struct holds 2 rules, for example, in a field like this: `Rules []Rule`.
|
||||
|
||||
Once that's all set up, register your middleware in [config/directives.go](https://github.com/mholt/caddy/blob/master/config/directives.go). The ordering is very important, so be sure to get it right!
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user