func hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "hello\\n")
}
func headers(w http.ResponseWriter, req *http.Request) {
for name, headers := range req.Header {
for _, h := range headers {
fmt.Fprintf(w, "%v: %v\\n", name, h)
}
}
}
func main() {
http.HandleFunc("/hello", hello)
http.HandleFunc("/headers", headers)
http.ListenAndServe(":8090", nil)
}
The main flow: ListenAndServe
listens on the TCP port, and then loops accepting new connections. For each new connection it spins a goroutine to serve it. Serving the connection involves a loop of:
http.Request
http.Request
to the user-defined handlerA handler is anything that implements the http.Handler interface:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
if handler == nil, then http.DefaultServeMux
is used as the handler. This is the default server mux - a global instance of the http.ServeMux
type held in the http package.
Incidentally, when our sample code registers handlers with http.HandleFunc, it registers them on this very same default mux. We could rewrite our sample server as follows, without using the default mux. The default mux is somewhat of a security risk; as a global it can be modified by any package your project imports.
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/hello", hello)
mux.HandleFunc("/headers", headers)
http.ListenAndServe(":8090", mux)
}
ServeMux
is just a Handler
what ListenAndServe
takes is a value implementing the http.Handler
interface. We could write the following server without any mux
type PoliteServer struct {
}
func (ms *PoliteServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome! Thanks for visiting!\\n")
}
func main() {
ps := &PoliteServer{}
log.Fatal(http.ListenAndServe(":8090", ps))
}
We can simplify our polite server even more by using http.HandlerFunc:
func politeGreeting(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome! Thanks for visiting!\\n")
}
func main() {
log.Fatal(http.ListenAndServe(":8090", http.HandlerFunc(politeGreeting)))
}
Just like PolitServer
, http.ServeMux
is a type implementing the http.Handler
interface. Here’s an outline:
ServeMux
keeps a sorted (by length) slice of { pattern, handler } pairs.