mas*_*ash 3 reverse-proxy http go

我想构建一个 http 反向代理,它检查 HTTP 正文并在此之后将 HTTP 请求发送到它的上游服务器。你怎么能在 go 中做到这一点?

初始尝试(跟随)失败,因为 ReverseProxy 复制传入的请求,修改它并发送,但正文已被读取。

func main() {
    backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        b, err := ioutil.ReadAll(r.Body)
        if err != nil {
            http.Error(w, fmt.Sprintf("ioutil.ReadAll: %s", err), 500)
            return
        }
        // expecting to see hoge=fuga
        fmt.Fprintf(w, "this call was relayed by the reverse proxy, body: %s", string(b))
    }))
    defer backendServer.Close()

    rpURL, err := url.Parse(backendServer.URL)
    if err != nil {
        log.Fatal(err)
    }

    proxy := func(u *url.URL) http.Handler {
        p := httputil.NewSingleHostReverseProxy(u)
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if err := r.ParseForm(); err != nil {
                http.Error(w, fmt.Sprintf("ParseForm: %s", err), 500)
                return
            }
            p.ServeHTTP(w, r)
        })
    }(rpURL)
    frontendProxy := httptest.NewServer(proxy)
    defer frontendProxy.Close()

    resp, err := http.Post(frontendProxy.URL, "application/x-www-form-urlencoded", bytes.NewBufferString("hoge=fuga"))
    if err != nil {
        log.Fatalf("http.Post: %s", err)
    }

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatalf("ioutil.ReadAll: %s", err)
    }

    fmt.Printf("%s", b)
}
// shows: "http: proxy error: http: ContentLength=9 with Body length 0"

然后我的下一个尝试是将整个正文读入 bytes.Reader 并使用它来检查正文内容,并在发送到上游服务器之前先查找开头。但随后我必须重新实现我想避免的 ReverseProxy。有没有其他优雅的方式?