Golang RoundTripper提供空答复

问题描述 投票:0回答:1

我建立了一个小的反向代理,将请求转发到同一台计算机上的另一个端口,并将结果传递回调用方。

就我而言,服务的结果是一个包含链接的简单html页面。由于反向代理在与服务不同的端口上运行,因此我必须调整链接。我尝试使用Transport的自定义实现来做到这一点:

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
    }

    // This works
    b = bytes.Replace(b, []byte("http://localhost:5000"), []byte("http://localhost:8080"), -1)

   // This doesn't
    b = bytes.Replace(b, []byte("api"), []byte("auth-api"), -1)

    resp.Body = ioutil.NopCloser(bytes.NewReader(b))
    resp.ContentLength = int64(len(b))

    return resp, nil
}

这是我在请求处理程序中初始化反向代理的方式:

proxy := httputil.NewSingleHostReverseProxy(target)
proxy.Transport = &transport{http.DefaultTransport}
proxy.ServeHTTP(res, req)

我的代码中的第一个替换有效。但是秒数会导致客户端再调用几次(通过多次击中断点来识别),但没有结果:

curl: (52) Empty reply from server

如果我取消评论

b = bytes.Replace(b, []byte("api"), []byte("auth-api"), -1)

一切正常,主机名将按预期替换。我尝试调试非常努力,但无法找出问题所在。如果在替换完成后将正文保存到文件中,那么一切似乎都很好,并且前缀也得到了交换。它只是无法通过响应传递它。

http go reverse-proxy
1个回答
0
投票

绝对不是我的代码有问题。我创建了一个最小的工作示例,该示例是完全独立的,可以由您中的任何人进行测试。如果您在第37行(第二个替换)中注释,则端口8080(反向代理)将不再响应。

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

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
    }

    // This works
    b = bytes.Replace(b, []byte("localhost:5000"), []byte("localhost:8080"), -1)

    // This doesn't
    // b = bytes.Replace(b, []byte("api"), []byte("auth-api"), -1)

    reader := bytes.NewReader(b)
    closer := ioutil.NopCloser(reader)
    body := closer
    resp.Body = body
    resp.ContentLength = int64(len(b))

    return resp, nil
}

func main() {
    infoPageServer := http.NewServeMux()
    infoPageServer.HandleFunc("/", serveHTML)

    reverseProxy := http.NewServeMux()
    reverseProxy.HandleFunc("/", serveProxy)

    // Running Info Page Server
    go func() {
        log.Println("Starting Info Page service on port 5000")
        http.ListenAndServe(":5000", infoPageServer)
    }()

    // Running Reverse Proxy Server
    log.Println("Starting Reverse Proxy service on port 8080")
    http.ListenAndServe(":8080", reverseProxy)
}

func serveHTML(resp http.ResponseWriter, req *http.Request) {
    const html = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Info Page</title>
  </head>
  <body>
    <pre>http://localhost:5000/api/</pre>
  </body>
</html>`
    fmt.Fprint(resp, html)
}

func serveProxy(resp http.ResponseWriter, req *http.Request) {
    target, err := url.Parse("http://localhost:5000")
    if err != nil {
        panic(err)
    }

    proxy := httputil.NewSingleHostReverseProxy(target)
    proxy.Transport = &transport{http.DefaultTransport}
    proxy.ServeHTTP(resp, req)
}
© www.soinside.com 2019 - 2024. All rights reserved.