Given that you have two instances of http.ServeMux
,
and you wish for them to be served at the same port number, like so:
muxA, muxB http.ServeMux
//initialise muxA
//initialise muxB
combinedMux := combineMux([muxA, muxB])
http.ListenAndServe(":8080", combinedMux)
How would one go about writing the combinedMux
function, as described above?
... or is there an alternative way to accomplish the same thing?
Handler (what http. Handle accepts) is an interface; http. HandlerFunc (what HandleFunc accepts) is a simple type that satisfies http. Handler . For example, I have appHandler type func (w http.
Whereas a servemux (also known as a router) stores a mapping between the predefined URL paths for your application and the corresponding handlers. Usually you have one servemux for your application containing all your routes. Go's net/http package ships with the simple but effective http.
The relevant type in net/http is type Handler interface { ServeHTTP(ResponseWriter, *Request) } an interface type. Any concrete type implementing this interface can be used to serve HTTP request. Your bar is of type foo and foo implements the Handler interface.
Because an http.ServeMux
is also an http.Handler
you can easily nest one mux inside another, even on the same port and same hostname. Here's one example of doing that:
rootMux := http.NewServeMux()
subMux := http.NewServeMux()
// This will end up handling /top_path/sub_path
subMux.HandleFunc("/sub_path", myHandleFunc)
// Use the StripPrefix here to make sure the URL has been mapped
// to a path the subMux can read
rootMux.Handle("/top_path/", http.StripPrefix("/top_path", subMux))
http.ListenAndServe(":8000", rootMux)
Note that without that http.StripPrefix()
call, you would need to handle the
whole path in the lower mux.
The SeverMux type is itself a http.Handler, therefore you can nest them easily. For example:
mux := NewServeMux()
mux.AddHandler("server1.com:8080/", muxA)
mux.AddHandler("server2.com:8080/", muxB)
I'm not quite sure what you mean exactly with "combining" them. If you want to try one handler first and then another one in case of 404, you might do it like this (untested):
mux := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rec := httptest.NewRecorder()
rec.Body = &bytes.Buffer{}
muxA.ServeHTTP(rec, r)
if rec.Code == 404 {
muxB.ServeHTTP(w, r)
return
}
for key, val := range rec.HeaderMap {
w.Header().Set(key, val)
}
w.WriteHeader(rec.Code)
rec.Body.WriteTo(w)
})
This has obviously some disadvantages like storing the whole response in memory. Alternatively, if you don't mind calling your handler twice, you can also set rec.Body = nil
, check just rec.Code
and call muxA.ServeHTTP(w, r)
again in case of success. But it's probably better to restructure your application so that the first approach (nested ServerMux) is sufficient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With