XHandler is a bridge between net/context and http.Handler
.
It lets you enforce net/context
in your handlers without sacrificing compatibility with existing http.Handlers
nor imposing a specific router.
Thanks to net/context
deadline management, xhandler
is able to enforce a per request deadline and will cancel the context when the client closes the connection unexpectedly.
You may create your own net/context
aware handler pretty much the same way as you would do with http.Handler.
This library is inspired by https://joeshaw.org/net-context-and-http-handler/.
go get -u github.com/rs/xhandler
package main
import (
"log"
"net/http"
"time"
"github.com/rs/cors"
"github.com/rs/xhandler"
"golang.org/x/net/context"
)
type myMiddleware struct {
next xhandler.HandlerC
}
func (h *myMiddleware) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
ctx = newContext(ctx, "World")
h.next.ServeHTTPC(ctx, w, r)
}
func main() {
var xh xhandler.HandlerC
// Inner handler (using handler func), reading from the context
xh = xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
value, _ := fromContext(ctx)
w.Write([]byte("Hello " + value))
})
// Middleware putting something in the context
xh = &myMiddleware{next: xh}
// Add close notifier handler so context is cancelled when the client closes
// the connection
xh = xhandler.CloseHandler(xh)
// Add timeout handler
xh = xhandler.TimeoutHandler(xh, 5*time.Second)
// Bridge context aware handlers with http.Handler using xhandler.Handle()
// This handler is now a conventional http.Handler which can be wrapped
// by any other non context aware handlers.
var h http.Handler
// Root context
ctx := context.Background()
h = xhandler.New(ctx, xh)
// As an example, we wrap this handler into the non context aware CORS handler
h = cors.Default().Handler(h)
http.Handle("/", h)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
How to use it with a non- net/context
aware router. Lets try with the Go's ServerMux
:
func main() {
mux := http.NewServeMux()
// Use xwrap to insert xhandler and all the intermediate context handlers
mux.Handle("/api/", xwrap(apiHandlerC{}))
mux.HandleFunc("/", xwrap(func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
}))
}
func xwrap(xh xhandler.HandlerC) http.Handler {
// Middleware putting something in the context
xh = &myMiddleware{next: xh}
ctx := context.Background()
return xhandler.New(ctx, xh)
}
Here is a list of net/context
aware middleware handlers implementing xhandler.HandlerC
interface.
Feel free to put up a PR linking your middleware if you have built one:
Middleware | Author | Description |
---|---|---|
xlog | Olivier Poitrey | HTTP handler logger |
xstats | Olivier Poitrey | A generic client for service instrumentation |
xaccess | Olivier Poitrey | HTTP handler access logger with xlog and xstats |
cors | Olivier Poitrey | Cross Origin Resource Sharing (CORS) support |
All source code is licensed under the MIT License.