http - http.RoundTripper 应该什么时候关闭它的连接?

标签 http go

我正在使用 httputil.ReverseProxyhttp.RoundTripper我自己的实现使用 ssh.Channel作为交通工具。我的 RoundTrip 方法大致如下所示:

func (c SSHConnection) RoundTrip(req *http.Request) (*http.Response, error) {
    ch, err := c.GetChannel()
    if err != nil {
        return nil, errors.New("couldn't open forwarded-tcpip channel: " + err.Error())
    }
    // defer ch.Close()
    err = req.Write(ch)
    if err != nil {
        return nil, errors.New("couldn't send request: " + err.Error())
    }

    return http.ReadResponse(bufio.NewReader(ch), req)
}

func (c SSHConnection) GetChannel() (ssh.Channel, error) {
    ch, req, err := c.Conn.OpenChannel("forwarded-tcpip", msg)
    if err != nil {
        return nil, err
    }
    go ssh.DiscardRequests(req)
    return ch, nil
}

注意注释掉的 defer ch.Close()。最初我天真地关闭了这里的连接,但响应主体有时会是空的,这是由于 HTTP 代理读取主体与关闭 SSH channel 之间的竞争。

假设,现在我不想保持事件状态,我什么时候可以关闭 ssh.Channel?如果我不这样做,每个请求都会启动一个新的 goroutine(因为 go ssh.DiscardRequests(req)),所以我会在每个 HTTP 请求上泄漏一个 goroutine,直到底层 SSH 连接关闭。

最佳答案

http.RoundTripper 不应该关闭连接,直到响应主体被完全消耗,或者在服务器请求时。

最简单的选择是完全缓冲响应并立即关闭连接。在某些情况下,如果流量主要由小型独立请求组成,这实际上可能是最有效的。

下一个选项是 Hook 响应主体的关闭以关闭 channel 。

type Body struct {
    io.ReadCloser
    channel ssh.Channel
}

func (b *Body) Close() error {
    b.channel.Close()
    return b.ReadCloser.Close()
}

func (c SSHConnection) RoundTrip(req *http.Request) (*http.Response, error) {
    ch, err := c.GetChannel()
    if err != nil {
        return nil, errors.New("couldn't open forwarded-tcpip channel: " + err.Error())
    }

    err = req.Write(ch)
    if err != nil {
        return nil, errors.New("couldn't send request: " + err.Error())
    }

    resp, err := http.ReadResponse(bufio.NewReader(ch), req)
    if err != nil {
        ch.Close()
        return nil, err
    }

    resp.Body = &Body{
        ReadCloser: resp.Body,
        channel:    ch,
    }
    return resp, err
}

最后,为了最有效地使用 ssh channel ,您可以使用现有的 Transportnet.Dialer 来建立 ssh 连接,并包装net.Conn 接口(interface)中的 channel 。

关于http - http.RoundTripper 应该什么时候关闭它的连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46834710/

相关文章:

java - 浏览器关闭时 Servlet 长处理取消

java - JSON 中 RestTemplate 中的 GET 请求

http - 批量请求 MIME 类型的 IIS 压缩设置 'multipart/mixed'

go - 评估/执行 Golang 代码/表达式,如 js 的 eval()

go - 无法评估字符串类型的字段 <field>

multithreading - 如何在http中使用多个进程

Java 和 PHP POST 请求不起作用

go - 锁定文件以更新一段数据或所有文件内容

for-loop - 转到如何正确使用 for ... range 循环

go - golang中net/http连接源码疑惑