The Go standard library defines two main components for dealing with incoming HTTP requests: the http.Handler
type and the http.HandlerFunc
type. While http.Handler
is an actual interface,
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http.HandlerFunc
, on the other hand, is just a type definition,
type HandlerFunc func(ResponseWriter, *Request)
which is even more flexible and allows the usage of ordinary functions as HTTP handlers, as long as they have that signature.
The way you implement your handler is really dependent on what you want to achieve and also the limitations of each approach.
Using the http.Handler
interface requires you to define a type which implements that interface in order for it to be treated as a Handler. Here's an example:
type foo struct {}
func (h *foo) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
}
Using the http.HandlerFunc
type is even easier, and requires you to simply have any function which respects the signature func(http.ResponseWriter, *http.Request)
passed to whoever is using the handlers. Here's an example, where Foo
is a valid HTTP handler:
func Foo(w http.ResponseWriter, req *http.Request) {}
In any case , once you have a valid handler, you can serve HTTP requests by writing very simple code (specifically, making use of the http.Handle
, http.HandleFunc
and/or the http.ListenAndServe
functions), which might look like this:
http.Handle("/foo", foo) // Assuming you implemented the http.Handler interface
http.HandleFunc("/foo", Foo) // Assuming you defined Foo as an http.HandlerFunc
log.Fatal(http.ListenAndServe(":8080", nil))
Here, nil
is being passed to http.ListenAndServe
so that internally it will use its default implementation defined in net/http
. The default implementation is a package instance variable of a another important component: the http.ServeMux
.