Go: Как совместить два (или более) http.ServeMux?
Учитывая, что у вас есть два случая http.ServeMux
и вы хотите, чтобы они обслуживались с одним и тем же номером порта, например:
muxA, muxB http.ServeMux
//initialise muxA
//initialise muxB
combinedMux := combineMux([muxA, muxB])
http.ListenAndServe(":8080", combinedMux)
Как можно было бы написать combinedMux
функция, как описано выше?
... или есть альтернативный способ сделать то же самое?
2 ответа
Потому что http.ServeMux
также http.Handler
Вы можете легко вложить один мультиплексор в другой, даже на тот же порт и то же имя хоста. Вот один из примеров этого:
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)
Обратите внимание, что без этого http.StripPrefix()
вызов, вам нужно будет обрабатывать весь путь в нижнем мультиплексоре.
Тип SeverMux сам по себе является http.Handler, поэтому вы можете легко их вложить. Например:
mux := NewServeMux()
mux.AddHandler("server1.com:8080/", muxA)
mux.AddHandler("server2.com:8080/", muxB)
Я не совсем уверен, что вы имеете в виду именно под "объединением" их. Если вы хотите сначала попробовать один обработчик, а затем другой в случае 404, вы можете сделать это следующим образом (не проверено):
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)
})
Это, очевидно, имеет некоторые недостатки, такие как хранение всего ответа в памяти. Кроме того, если вы не против дважды вызвать ваш обработчик, вы также можете установить rec.Body = nil
проверь просто rec.Code
и позвонить muxA.ServeHTTP(w, r)
снова в случае успеха. Но, вероятно, лучше реструктурировать ваше приложение, чтобы первого подхода (вложенного ServerMux) было достаточно.