How to build an http reverse proxy to dynamically change the content of the upstream response?

I’m thinking about creating something like this.

proxy := &httputil.ReverseProxy{
	Director:  director,
	Transport: &proxyTransport{},

server := http.Server{
	Addr:    ":6060",
	Handler: proxy,

And the function func director(r *http.Request){} will change the URL of the request and the custom http.Transport will get the body of the upstream response, does the necessary modifications and sends down a new response.

func director(r *http.Request){
  r.URL = url.Parse("")


type proxyTransport struct {

func (p *proxyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  res, err := trans.RoundTrip(req)
  if err != nil {
    return nil, err

  body, err := httputil.DumpResponse(res, true)
  if err != nil {
    return nil, err

 nbody := &bytes.Buffer{}
 nbody.Write(append(body, []byte("foo")...))
 b := ioutil.NopCloser(nbody)

  nres := &http.Response{
	StatusCode: http.StatusOK,
	Status:     fmt.Sprintf("%d %s", http.StatusOK, http.StatusText(http.StatusOK)),
	Proto:      "HTTP/1.1",
	ProtoMajor: 1,
	ProtoMinor: 1,
	Header:     http.Header{},
	Body:       b,
	Request:    req,
  return nres, nil

Is this the correct way to go? What other things I need to take care of to not to screw up the performance?

Perhaps better for performance is to implement a Reader that modifies the data before it’s written to the buffer, so that you don’t have to read the whole response body in memory at once.

This for example willl read something before and after the reader you are wrapping:

If you want to modify the body itself, you probably have to load it all in memory anyway.

PS: in making your Response you don’t need to set some fields, like the protocol and the status twice. You are also discarding all the received response headers.


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.