我用
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连接。
答案 0 :(得分:5)
不要使用劫持,因为一旦劫持,HTTP服务器库就不会对连接做任何其他事情,所以无法重用。
我改变方式,复制标题和正文,看起来像反向代理(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)
}
答案 1 :(得分:0)
似乎一旦连接关闭,保持连接也会关闭。 一种可能的解决方案是防止连接关闭直到需要,但我不确定是否有好的建议。
也许正确的解决方案涉及创建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)
}