2015-07-21 15 views

cevap

16

httputil.ReverseProxy bir Transport alan var. Yanıtı değiştirmek için kullanabilirsiniz. Bütün bunların

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} 

Bahçesi Örneğin: http://play.golang.org/p/b0S5CbCMrI Örneğin.

+2

* small * nit, 'b', daha küçük bir yapı olan bytes.NewReader' ile sarılabilir. – JimB

+0

Düzenlendi, teşekkürler. –

3

En iyi çözümü bilmiyorum. Ama böyle bir şey yapabilirsiniz:

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) 
} 
+0

. Hala tüm akışı elde etmek için başka bir 'io.Writer' içine kopyalamanız gerekir; Neyse ki zaten bunun için bir şey var: [io.TeeReader] (http://golang.org/pkg/io/#TeeReader). (veya yanıtı istiyorsanız * yeni bir RoundTripper yapın * önce * yazılıyor) – JimB

+0

Evet, tabiki. Sadece fikri gösteriyorum. Şahsen ben, Ainar-G çözümünün benimkinden daha iyi olduğunu düşünüyorum. – RoninDev

+0

OP'nin sorusunun bu cevabı atmak için yeterince açık olduğunu sanmıyorum, özellikle de vücudun bir bütün olarak dizeye yazılması gerektiğini söylemiyor; Bu örnek, biraz fazla şişmiş olsa da, yanıt akışını nasıl yakalayacağını gösterir. Yanıt gövdesini anında tutmak ve gerçekleştirmek için iyi bir çözüm, örneğin, bazı kodlama/kod çözme. – tomasz

5

şimdi httputil/ters vekil sunucusu, daha destek, source bakınız Bu yalnızca bir defada gövde bir öbek yazdırmak için yönetir

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