Skip to content

Instantly share code, notes, and snippets.

@thezelus
Last active January 12, 2023 07:27
Show Gist options
  • Save thezelus/d5ac9ec563b061c514dc to your computer and use it in GitHub Desktop.
Save thezelus/d5ac9ec563b061c514dc to your computer and use it in GitHub Desktop.
golang NewSingleHostReverseProxy + gorilla mux
package main
import (
"net/http"
"net/http/httputil"
"net/url"
"github.com/gorilla/mux"
)
//Target url: https://httpbin.org/headers
//Url through proxy: http://localhost:3002/forward/headers
func main() {
target := "https://httpbin.org"
remote, err := url.Parse(target)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
r := mux.NewRouter()
r.HandleFunc("/forward/{rest:.*}", handler(proxy))
http.Handle("/", r)
http.ListenAndServe(":3002", r)
}
func handler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = mux.Vars(r)["rest"]
p.ServeHTTP(w, r)
}
}
@jaecktec
Copy link

I think the handler is not complete. It should be:

func handler(target string, p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		r.URL.Host = url.Host
		r.URL.Scheme = url.Scheme
		r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
		r.Host = url.Host

		r.URL.Path = mux.Vars(r)["rest"]
		p.ServeHTTP(w, r)
	}
}

@sonufrienko
Copy link

@jaecktec Thanks for sharing. This header was a missing part of my code. You saved my day!

@evzpav
Copy link

evzpav commented Dec 13, 2022

A more complete version of the above:


import (
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/gorilla/mux"
)

// package main

// import (
// 	"net/http"

// 	"github.com/gorilla/mux"
// )

// func main() {
// 	r := mux.NewRouter()
// 	r.HandleFunc("/actions", func(w http.ResponseWriter, r *http.Request) {
// 		w.Write([]byte("actions"))
// 		w.WriteHeader(200)
// 	})
// 	http.Handle("/", r)
// 	http.ListenAndServe(":3333", r)
// }

// Run server above
// call curl http://localhost:3222/target/actions
// Url through proxy:  http://localhost:3333/actions

func main() {
	target := "http://localhost:3333"
	remote, err := url.Parse(target)
	if err != nil {
		panic(err)
	}

	proxy := httputil.NewSingleHostReverseProxy(remote)
	r := mux.NewRouter()

	r.HandleFunc("/target/{forward:.*}", proxyHandler(remote, proxy))
	http.Handle("/", r)

	http.ListenAndServe(":3222", r)
}

func proxyHandler(url *url.URL, p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		r.URL.Host = url.Host
		r.URL.Scheme = url.Scheme
		r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
		r.Host = url.Host

		r.URL.Path = mux.Vars(r)["forward"]
		p.ServeHTTP(w, r)
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment