Об угоне http и поддержании жизни
Я использую
resp, err := http.Get("http://example.com/")
получить http.Response, и я хочу точно написать в обработчик http, но только http.ResponseWriter, так что я угоняю его.
...
webConn, webBuf, err := hj.Hijack()
if err != nil {
// handle error
}
defer webConn.Close()
// Write resp
resp.Write(webBuf)
...
Написать необработанный запрос
Но когда я угоняю, http-соединение не может повторно использоваться (keep-alive), поэтому оно медленное.
Как решить?
Спасибо! Извините за мой бассейн английский.
обновление 12/9 keep-alive, он поддерживает два TCP-соединения и может использовать повторно.
но когда я угоняю, и conn.Close(), он не может повторно использовать старое соединение, поэтому он создает новое соединение TCP, когда я каждый обновляю.
2 ответа
Не используйте hijack, потому что однажды hijack, библиотека HTTP-сервера больше ничего не будет делать с соединением, поэтому не может использовать повторно.
Я меняю способ, копирую Header и Body, выгляжу как обратный прокси ( http://golang.org/src/pkg/net/http/httputil/reverseproxy.go), работает.
Пример:
func copyHeader(dst, src http.Header) {
for k, w := range src {
for _, v := range w {
dst.Add(k, v)
}
}
}
func copyResponse(r *http.Response, w http.ResponseWriter) {
copyHeader(w.Header(), r.Header)
w.WriteHeader(r.StatusCode)
io.Copy(w, r.Body)
}
func handler(w http.ResponseWriter, r *http.Response) {
resp, err := http.Get("http://www.example.com")
if err != nil {
// handle error
}
copyResponse(resp, w)
}
Кажется, что как только соединение закрыто, соединение keep-alive также закрывается. Одним из возможных решений было бы предотвращение закрытия соединения до желаемого, но я не уверен, что это хороший совет.
Возможно, правильное решение включает создание экземпляра net.TCPConn, копирование соединения через него, а затем вызов .SetKeepAlive(true)
,
Перед запуском приведенного ниже примера запустите другой терминал с netstat -antc | grep 9090
,
Маршруты в примере:
localhost:9090/ok
является основным (не угнанным) соединениемlocalhost:9090
это захваченное соединение, продолжающееся 10 секунд.
пример
package main
import (
"fmt"
"net/http"
"sync"
"time"
)
func checkError(e error) {
if e != nil {
panic(e)
}
}
var ka_seconds = 10
var conn_id = 0
func main() {
http.HandleFunc("/ok", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "ok")
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
conn_id++
fmt.Printf("Connection %v: Keep-alive is enabled %v seconds\n", conn_id, ka_seconds)
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Don't forget to close the connection:
time.AfterFunc(time.Second* time.Duration(ka_seconds), func() {
conn.Close()
fmt.Printf("Connection %v: Keep-alive is disabled.\n", conn_id)
})
resp, err := http.Get("http://www.example.com")
checkError(err)
resp.Write(bufrw)
bufrw.Flush()
})
fmt.Println("Listing to localhost:9090")
http.ListenAndServe(":9090", nil)
}
Связанная проблема: http://code.google.com/p/go/issues/detail?id=5645