宝慕林4294392
如果客户端断开连接,则 gin.Context.Done() 返回。http.Transport.CancelRequest() 中断对 url 的 http 请求。所以 http 请求是在 goroutine 中发出的,我们等待 select 中的第一个事件:http请求完成客户端与 gin 服务器断开连接router.GET("/v1/get/*uri", func (c *gin.Context) { var url = c.Param("uri") if url[0:1] == "/" { url = url [1:]} tr := &http.Transport{ TLSClientConfig : (&tls.Config{ InsecureSkipVerify: true}), DisableKeepAlives : false, DisableCompression : false, MaxIdleConns : 0, MaxConnsPerHost : 0, IdleConnTimeout : 0, ResponseHeaderTimeout : 0, ExpectContinueTimeout : 0, ForceAttemptHTTP2 : true} client := http.Client{ Timeout: 20 * time.Second, Transport : tr} req, err := http.NewRequest("GET", url, nil) if err != nil { fail(1, "NewRequest") } for k, v := range c.Request.Header { req.Header.Set(k, strings.Join(v, "\n")) } is_url_done := make(chan HTTPRequestResult, 1) go func() { resp, err := client.Do(req) is_url_done <- HTTPRequestResult{res, err} }() for { select { case <-c.Done(): tr.CancelRequest(req) return case r:= <-is_url_done: if r.err != nil { c.String(http.StatusInternalServerError, "Error: %v\n", r.err) } else { var headers = map[string]string{} for key, values := range(r.res.Header) { headers[key] = strings.Join(values, ", ") } c.DataFromReader(r.res.StatusCode, r.res.ContentLength, "test", r.res.Body, headers) } return }}