2015-07-21 12 views
10
package main 

import (
    "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", proxy) 
    http.ListenAndServe(":8099", nil) 
} 

Reverse Proxy funktioniert. Wie kann ich den Antwortkörper erhalten?Golang: Wie Antwort Körper von ReverseProxy lesen?

Antwort

16

httputil.ReverseProxy ein Transport Feld hat. Sie können damit die Antwort ändern. Zum Beispiel:

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} 

Spielplatz Beispiel für die ganze Sache: http://play.golang.org/p/b0S5CbCMrI.

+2

* small * nit, 'b' kann mit' bytes.NewReader' umschlossen werden, was eine etwas kleinere Struktur ist. – JimB

+0

Bearbeitet, danke. –

3

Ich weiß nicht die beste Lösung. Aber man kann etwas tun:

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

Dies gelingt nur zu einem Zeitpunkt aus dem Körper eines Klumpen zu drucken. Sie müssten es immer noch in einen anderen "io.Writer" kopieren, um den gesamten Stream zu erhalten; Zum Glück gibt es schon etwas dafür: [io.TeeReader] (http://golang.org/pkg/io/#TeeReader). (oder machen Sie einen neuen RoundTripper, wenn Sie die Antwort * vor * es ist geschrieben werden wollen) – JimB

+0

Ja, natürlich. Ich zeige nur die Idee. Ich persönlich denke, dass @ Ainar-G-Lösung besser ist als meine. – RoninDev

+0

Ich glaube nicht, dass die Frage von OP klar genug ist, um diese Antwort zu verwerfen, insbesondere heißt es nicht, dass der Körper als Ganzes in die Zeichenkette geschrieben werden sollte; Dieses Beispiel zeigt, obwohl etwas zu aufgebläht, wie der Antwortstream erfasst werden kann. Gute Lösung, um den Antwortkörper im laufenden Betrieb zu erreichen und zum Beispiel einige Codierungen/Decodierungen durchzuführen. – tomasz

5

jetzt HTTPUTIL/Reverse Proxy, Unterstützung als siehe Quelle

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