Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active April 28, 2022 12:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/4b5c0cb47657e0a80d25ab6369174c72 to your computer and use it in GitHub Desktop.
Save Integralist/4b5c0cb47657e0a80d25ab6369174c72 to your computer and use it in GitHub Desktop.
[Golang ReverseProxy] #go #golang #reverseproxy
package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
)
func main() {
http.HandleFunc("/", proxyFunc)
log.Fatal(http.ListenAndServe(":8888", nil))
}
func proxyFunc(w http.ResponseWriter, r *http.Request) {
if r.URL.Scheme == "" {
r.URL.Scheme = "https"
}
if r.URL.Host == "" {
r.URL.Host = "httpbin.org"
r.Host = "httpbin.org"
}
fmt.Printf("url: %+v\n", r.URL)
proxy := httputil.NewSingleHostReverseProxy(r.URL)
proxy.ServeHTTP(w, r)
}
// https://play.golang.org/p/pk1FOh563jJ
package main
import (
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"strings"
"time"
)
// copied from https://golang.org/src/net/http/httputil/reverseproxy.go?s=3330:3391#L98
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
func main() {
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "backend server handled the request!")
}))
defer backendServer.Close()
backendServerURL, err := url.Parse(backendServer.URL)
if err != nil {
log.Fatal(err)
}
proxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Scheme = backendServerURL.Scheme
r.URL.Host = backendServerURL.Host
r.URL.Path = singleJoiningSlash(backendServerURL.Path, r.URL.Path)
},
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 10 * time.Second,
}).Dial,
},
ModifyResponse: func(r *http.Response) error {
// return nil
//
// purposefully return an error so ErrorHandler gets called
return errors.New("uh-oh")
},
ErrorHandler: func(rw http.ResponseWriter, r *http.Request, err error) {
fmt.Printf("error was: %+v (going to 302 redirect to google now)", err)
http.Redirect(rw, r, "http://www.google.com", 302)
},
}
frontendServer := httptest.NewServer(proxy)
defer frontendServer.Close()
resp, err := http.Get(frontendServer.URL)
if err != nil {
log.Fatal(err)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment