我使用httputil.ReverseProxy與我自己實現的http.RoundTripper,它使用ssh.Channel作爲傳輸。我的RoundTrip方法大致如下所示:http.RoundTripper何時應關閉其連接?
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
}
請注意註釋掉的延遲ch.Close()。最初,我天真地關閉了這裏的連接,但由於HTTP代理讀取正文和關閉SSH通道之間的競爭,響應主體有時會是空的。
現在假設我不在乎保持活力,何時關閉ssh.Channel?如果我不這樣做,每個請求都會啓動一個新的goroutine(因爲執行ssh.DiscardRequests(req)),所以我在每個HTTP請求上泄漏一個goroutine,直到底層SSH連接關閉。
我沒有想到這一點,但Response.Body只是一個io.ReadCloser。也許你可以包裝默認的Close()方法。然後你就會知道調用者何時完成響應,並且你可以關閉連接。 – Peter
是的,這取決於客戶端使用和關閉'Response.Body',但關閉它並不直接關閉連接,它只會將它從主體中釋放。我認爲如果你想在這一層處理連接,而不是在傳輸層,你需要緩存整個響應並在RoundTrip中關閉連接。是否有一個原因,你不是簡單地使用SSH作爲網絡傳輸? – JimB
@Peter好主意;實施和工作。也許值得回答? –