Skip to content

Repository files navigation

Release Reference DeepWiki Test

Insights Insights

go-httpproxy

Flexible and powerful http proxy library for Go.

Features

  • Reverse proxy handler.
  • Custom error handler
  • No panics (unlike net/http/httputil.ReverseProxy).
  • Proxy streaming requests and responses.
    • WebSocket is supported
    • SSE (Server Sent Event) is supported
    • And more
  • 101 protocol upgrade support

Usages

The basic Proxy struct. It implements http.Handler interface.

// Proxy is an HTTP proxy.
// It implements [net/http.Handler].
type Proxy struct {
    // The transport used to perform proxy requests.
    // If nil, [net/http.DefaultTransport] is used.
    Transport http.RoundTripper
    // PreRoundTrip is called just before roundtrip.
    // In request must not be modified in the function.
    // Out request can be modified in the function.
    // PreRoundTrip can be used for rewriting request url
    // or changing request context and so on.
    // Proxy stops proceeding the request when PreRoundTrip
    // returns non-nil error and calls ErrorHandler.
    PreRoundTrip func(*ProxyRequest) error
    // PostRoundTrip is called just after roundtrip.
    // The given response is the response from backend.
    // In and Out requests must not be modified in PostRoundTrip.
    // In holds the frontend-side request and response.
    // Out holds the backend-side request and response.
    PostRoundTrip func(*In, *Out) error
    // ErrorHandler is the optional error handler.
    // If non-nil, any errors occurred while proxying is given.
    // If nil, a default error handler is used.
    // The ResponseWriter will be nil when response is not writable.
    ErrorHandler func(http.ResponseWriter, *http.Request, *Error)
}

func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
func (p *Proxy) handleError(w http.ResponseWriter, r *http.Request, err *Error)

Built-in round-robin proxy

This example shows how to use built-in simple round-robin proxy.

proxy, err := httpproxy.NewProxy("http://localhost:8081/", "http://localhost:8082/")
if err != nil {
    panic(err)
}

log.Println("proxy server is listening at: localhost:8080")
if err := http.ListenAndServe(":8080", proxy); err != nil && err != http.ErrServerClosed {
    panic(err)
}

Rewrite request target

To change the proxy targets, or proxy bachends, use PreRoundTrip hook.

Target urls, request context and request body and other request info can be modified.

target, _ := url.Parse("http://localhost:9999")

proxy := &Proxy{
    PreRoundTrip: func(pr *ProxyRequest) error {
        httpproxy.RewriteURL(pr.Out.URL, target)
        httpproxy.SetForwardedHeader(pr.In, pr.Out.Header)
        httpproxy.SetXForwardedHeaders(pr.In, pr.Out.Header)
        return nil
    }
}

Custom error handler

Use ErrorHandler of the Proxy object.

For example:

target, _ := url.Parse("http://localhost:9999")
proxy := &httpproxy.Proxy{
    PreRoundTrip: func(pr *httpproxy.ProxyRequest) error {
        httpproxy.RewriteURL(pr.Out.URL, target)
        return nil
    },
    ErrorHandler: func(w http.ResponseWriter, r *http.Request, err *httpproxy.Error) {
        log.Println("ERROR:", err)
        if w == nil || !err.Writable() {
            return
        }
        var status int
        switch err.Cause {
        case httpproxy.ErrPreRoundTrip, httpproxy.ErrPostRoundTrip:
            status = http.StatusInternalServerError
        case httpproxy.ErrRoundTrip:
            fallthrough
        default:
            status = http.StatusBadGateway
        }
        w.WriteHeader(status)
        _, _ = w.Write([]byte(http.StatusText(status)))
    },
}

Docs & Examples

References