golang proxy timeout的问题

需求:
golang实现proxy来做到前端请求某个url后落到proxy上,proxy再发起请求到backend server, 然后为了性能问题, 我需要考虑超时后放弃后端返回,以及提醒http client超时(504)

我的思路:

target, err := url.Parse(backend)  
if err != nil {  
   fmt.Printf("backend %s parse errr : %v\n", backend, err)  
}  
  
reserveProxy := httputil.NewSingleHostReverseProxy(target)  
reserveProxy.Transport = Transport{cfg}  
c.Request.Host = target.Host  
c.Request.URL.Path = newReqpath  
  
reserveProxy.ServeHTTP(c.Writer, c.Request)
proxyTransport := http.Transport{  
   Proxy:                  http.ProxyFromEnvironment,  
   DialContext: (&net.Dialer{  
      Timeout:   3 * time.Second,  
      KeepAlive: 30 * time.Second,  
      Deadline: time.Now().Add(3 * time.Second),  
   }).DialContext,  
  
   ForceAttemptHTTP2:     true,  
   MaxIdleConns:          100,  
   IdleConnTimeout:       90 * time.Second,  
   TLSHandshakeTimeout:   10 * time.Second,  
   ExpectContinueTimeout: 1 * time.Second,  
}  
return proxyTransport.RoundTrip(r)

我试图使用golang自带的reserveproxy来做proxy,并且利用transporttimeout,但是整个请求完全没有超时的作用(模拟一个接口20s,整个proxy就20s返回给http client)

寻找思路:
github issue
stackoverflow

发现有人和我遇到同样的问题,但是没有解决

所以这是不是golang的一个bug,还是我的使用不当?

阅读 7.8k
3 个回答

有一定的思考不错


你给的 github issue 其实已经回答了你的问题,可能你没有认真看:

net.Dialer 中的配置都是配置 TCP 的,其中 Timeout 指的是 TCP connect 时的超时时间,KeepAlive 指的是 TCP 连接无数据可以保持的时间,等等

而你想要的是无论是 TCP connect 还是 HTTP response,只要 3s 无数据就要中断操作

所以,你配置的 Timeout 3s 可以针对 TCP connect 有用;除此之外,你还可以将 KeepAlive 配置成 3s,来处理 HTTP 无响应的情况(这可能有用,也可能没用,取决于你的操作系统)

此外,你还可以配置 http.Transport 中的 IdleConnTimeout 来让空闲连接超时

proxy 干不了这件事情。

proxy 只是负责转发,也许可能有点小的修改。它会收到多少转发多少,而不是收到所有内容之后再发送。所以,等 timeout 过后,proxy 已经转发了一部分内容,这是 proxy 以及没有能力发送一个 504 了。它所能做的最多是强行中断连接,造成访问者看到一个网络错误。

如果等收到所有内容后再转发,只能使延迟更长。比如经过 3s 收到了所有内容,然后再转发可能还需要 3s (也许更长,也许更短),再访问者看来,整个连接用了 6s 。所以 proxy 通常不使用这种方式。

504 通常会用于过了一定的 timeout 还没能成功建立连接,或者还没有收到任何一个字节返回的情况。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题