Reputation: 2047
I'm trying to do a load balancer to study some go packages.
I want to handle errors when the request timeout or give 404 error but can't find how to do that.
func main() {
// start server
http.HandleFunc("/", handleRequestAndRedirect)
if err := http.ListenAndServe(getListenAddress(), nil); err != nil {
panic(err)
}
}
func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
ur, _ := url.Parse("https://www.instagram.com/")
proxy := httputil.NewSingleHostReverseProxy(ur)
// Update the headers to allow for SSL redirection
req.URL.Host = ur.Host
req.URL.Scheme = ur.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Host = ur.Host
req.Header.Set("Key", "Teste")
proxy.ServeHTTP(res, req)
}
Upvotes: 0
Views: 1908
Reputation: 123
As I ended up here looking for a way to handle 404 errors from the proxied host, I would like to complement the accepted answer, if it may be of any help for people landing on this page.
As stated in the official documentation (https://golang.org/pkg/net/http/httputil/#ReverseProxy):
ModifyResponse is an optional function that modifies the Response from the backend. It is called if the backend returns a response at all, with any HTTP status code. If the backend is unreachable, the optional ErrorHandler is called without any call to ModifyResponse. If ModifyResponse returns an error, ErrorHandler is called with its error value. If ErrorHandler is nil, its default implementation is used.
So if you want to catch not only "real" errors (host not reachable) but also error response codes from the server (404, 500...) you should use ModifyResponse
to check the response status code and return an error, which will be then catched by your ErrorHandler
function. The accepted answer example becomes:
func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
ur, _ := url.Parse("https://www.instagram.com/")
proxy := httputil.NewSingleHostReverseProxy(ur)
// Update the headers to allow for SSL redirection
req.URL.Host = ur.Host
req.URL.Scheme = ur.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Host = ur.Host
req.Header.Set("Key", "Teste")
proxy.ErrorHandler = ErrHandle
proxy.ModifyResponse = ModifyResponse
proxy.ServeHTTP(res, req)
}
func ModifyResponse(res *http.Response) error {
if res.StatusCode == 404 {
return errors.New("404 error from the host")
}
return nil
}
func ErrHandle(res http.ResponseWriter, req *http.Request, err error) {
fmt.Println(err)
}
Upvotes: 2
Reputation: 24
use proxy.ErrorHandler
ErrorHandler func(http.ResponseWriter, *http.Request, error)
func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
ur, _ := url.Parse("https://www.instagram.com/")
proxy := httputil.NewSingleHostReverseProxy(ur)
// Update the headers to allow for SSL redirection
req.URL.Host = ur.Host
req.URL.Scheme = ur.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Host = ur.Host
req.Header.Set("Key", "Teste")
proxy.ErrorHandler = ErrHandle
proxy.ServeHTTP(res, req)
}
func ErrHandle(res http.ResponseWriter, req *http.Request, err error) {
fmt.Println(err)
}
Upvotes: 1