Golang: how to read response body of ReverseProxy?
httputil.ReverseProxy
has a Transport
field. You can use it to modify the response. For example:
type transport struct {
http.RoundTripper
}
func (t *transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
resp, err = t.RoundTripper.RoundTrip(req)
if err != nil {
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
b = bytes.Replace(b, []byte("server"), []byte("schmerver"), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
resp.Body = body
resp.ContentLength = int64(len(b))
resp.Header.Set("Content-Length", strconv.Itoa(len(b)))
return resp, nil
}
// ...
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.Transport = &transport{http.DefaultTransport}
Playground example of the whole thing: http://play.golang.org/p/b0S5CbCMrI.
now httputil/reverseproxy, support than, see source
type ReverseProxy struct {
...
// ModifyResponse is an optional function that
// modifies the Response from the backend
// If it returns an error, the proxy returns a StatusBadGateway error.
ModifyResponse func(*http.Response) error
}
func rewriteBody(resp *http.Response) (err error) {
b, err := ioutil.ReadAll(resp.Body) //Read html
if err != nil {
return err
}
err = resp.Body.Close()
if err != nil {
return err
}
b = bytes.Replace(b, []byte("server"), []byte("schmerver"), -1) // replace html
body := ioutil.NopCloser(bytes.NewReader(b))
resp.Body = body
resp.ContentLength = int64(len(b))
resp.Header.Set("Content-Length", strconv.Itoa(len(b)))
return nil
}
// ...
target, _ := url.Parse("http://example.com")
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.ModifyResponse = rewriteBody
I don't know best solution. But you can do something like this:
package main
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
target := &url.URL{Scheme: "http", Host: "www.google.com"}
proxy := httputil.NewSingleHostReverseProxy(target)
http.Handle("/google", CustomHandler(proxy))
http.ListenAndServe(":8099", nil)
}
func CustomHandler(h http.Handler) http.HandlerFunc {
return func(res http.ResponseWriter, req *http.Request) {
h.ServeHTTP(NewCustomWriter(res), req)
}
}
type customWriter struct {
http.ResponseWriter
}
func NewCustomWriter(w http.ResponseWriter) *customWriter {
return &customWriter{w}
}
func (c *customWriter) Header() http.Header {
return c.ResponseWriter.Header()
}
func (c *customWriter) Write(data []byte) (int, error) {
fmt.Println(string(data)) //get response here
return c.ResponseWriter.Write(data)
}
func (c *customWriter) WriteHeader(i int) {
c.ResponseWriter.WriteHeader(i)
}