【问题标题】:How to implement HTTP forwarding Proxy in Go如何在 Go 中实现 HTTP 转发代理
【发布时间】:2021-07-16 14:05:02
【问题描述】:

我想为此实现一个HTTP请求和响应系统

client ------> A ----------> B --------> (request) HTTPserver
client <------ A <---------- B <-------- (response) HTTPserver
  1. 客户端使用任何 HTTP 方法(POST、PUT 等)向 A 发送 HTTP 请求
  2. A 然后读取请求正文加密它,然后将其转发给 B 3 B 然后解密读取的HTTP请求正文
  3. B 然后将接收到的解密正文作为有效负载准备 HTTP 请求并发送到 HTTP 服务器。 5 HTTP 服务器然后响应 B。
  4. B 然后加密来自 HTTP 服务器的响应,然后转发给 A。
  5. A 还解密来自 B 的响应,然后将响应发送回客户端。

我已经根据之前的建议实现了以下内容。

ProxyA:

const (
  ServerB = "<address of B>"
  Port = "<proxy A port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
 
 // read request body from client
bodybytes, _ := ioutil.ReadAll(req.Body)

defer req.Body.Close()

// encrypt req.Body
object, _ := enc.Encrypt(bodybytes)

// serialize object
serialized, _ := object.CompactSerialize()

// prepare forwarding message
msg := message{reformatedData: serialized}

// encode message 
msgbytes, _ := json.Marshal(&msg)

req.ContentLength = int64(len(msgbytes))
req.Body = ioutil.NopCloser(bytes.NewBuffer(msgbytes))


// How do I read the response data from proxy server B and then send
// response to the client
....
 
  url, _ := url.Parse(ServerB)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
}

For proxy B:

const (
  Server = "<address of server>"
  Port = "<proxy B port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {

  var msg message
  HTTPServerurl := http://xxxxx

  // read request body
  bodybytes, _ := ioutil.ReadAll(req.Body)
  
  req.ContentLength = int64(len(bodybytes))
  req.Body = ioutil.NopCloser(bytes.NewBuffer(bodybytes))


// decode message 
err = json.Unmarshal(bodybytes, &msg)

// decrypt message
object, _ := jose.ParseEncrypted(msg)
decrypted, _ := object.Decrypt("phrasetodecryptmessage")

//send HTTP request to HTTP server
resp, _ := HandlemessageToHTTPServer(decrypted, "POST", HTTPServerurl)

//read response body
RespBody, _ := ioutil.ReadAll(resp.Body)

// encrypt response body
object, _ = enc.Encrypt(producerRespBody)
serialized, _ := object.CompactSerialize()

// prepare response JSON message 
resmsg := resmessage {resmessage: serialized}

// marshall response message 
respmsgbytes, _ := json.Marshal(&resmsg)


// How do I write the "respmsgbytes" to proxyServHTTP "res" back to proxy A


  url, _ := url.Parse(Server)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

我的问题是

  1. 如何将代理B中的“respmsgbytes”写入proxyServHTTP“res”返回代理A?

  2. 如何从代理服务器 B 读取响应数据然后发送 回复客户?

有什么帮助吗?我留下了错误检查以使代码简短。

【问题讨论】:

  • 您可能会发现 stdlib httputil.ReverseProxy 很有用

标签: http go


【解决方案1】:

您可以使用httputil
您可以执行以下操作。
对于代理 A:

const (
  ServerB = "<address of B>"
  Port = "<proxy A port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
  // Encrypt Request here
  // ...

  url, _ := url.Parse(ServerB)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

对于代理 B:

const (
  Server = "<address of server>"
  Port = "<proxy B port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
  // Decrypt Request here
  // ...

  url, _ := url.Parse(Server)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

编辑:
要在每个代理处处理请求正文,您可以查看this。或者,我认为基于当前 req 构建新 req 应该没有害处,如下所示:

func proxyPass(res http.ResponseWriter, req  *http.Request) {
    body, _ := ioutil.ReadAll(req.Body)
    data := string(body)

    // process data here

    req, _ = http.NewRequest(req.Method, req.URL.String(), strings.NewReader(data))
    
    u, _ := url.Parse(Server)
    proxy := httputil.NewSingleHostReverseProxy(u)
    proxy.ServeHTTP(res, req)
}

这可以在两个代理上完成。

编辑:
可以使用 ReverseProxy.ModifyResponse 更新代理响应。
你可以这样使用它:

func proxyPass(res http.ResponseWriter, req *http.Request) {
    ....
    
    proxy := httputil.NewSingleHostReverseProxy(url)
    
    proxy.ModifyResponse = func(response *http.Response) error {
        // Read and update the response here

        // The response here is response from server (proxy B if this is at proxy A)
        // It is a pointer, so can be modified to update in place
        // It will not be called if Proxy B is unreachable
    }

    proxy.ServeHTTP(res, req)
}

【讨论】:

  • 出现错误:httputil: ReverseProxy 在正文复制期间读取错误:读取 tcp 127.0.0.1:52484->127.0.0.1:2020: 读取:对等方重置连接
  • 你是如何连接的?错误是connection reset by peer,意思是出于某种原因,客户端似乎发送RST
  • 抱歉,使用 http.ListenAndServeTLS 而不是 http.ListenAndServe 是我的错。
  • 但是,请求加密后,如何发送给代理B?
  • 您必须使用请求正文并更新请求本身。我会直接更新当前请求。
猜你喜欢
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 2021-12-29
  • 1970-01-01
相关资源
最近更新 更多