about http hijacking and keep-alive

huangapple go评论91阅读模式
英文:

about http hijacking and keep-alive

问题

我使用以下代码:

resp, err := http.Get("http://example.com/")

// 获取 http.ResponseWriter
webConn, webBuf, err := hj.Hijack()
if err != nil {
    // 处理错误
}
defer webConn.Close()

// 将 resp 写入 webBuf
resp.Write(webBuf)

我想要将获取到的 http.Response 写入到 http.ResponseWriter 中,但是只有 http.ResponseWriter,所以我使用了 hijack 来实现。

然而,当我使用 hijack 后,HTTP 连接无法重用(keep-alive),导致速度变慢。

如何解决这个问题呢?

对不起,我的英语不太好。

更新 12/9
about http hijacking and keep-alive
about http hijacking and keep-alive
keep-alive,它保持两个 TCP 连接,并且可以重用。

about http hijacking and keep-alive
about http hijacking and keep-alive
但是当我使用 hijack 并关闭连接(conn.Close())后,无法重用旧的连接,所以每次刷新时都会创建一个新的 TCP 连接。

英文:

i use

resp, err := http.Get("http://example.com/")

get a http.Response, and i want to exactly write to a http handler, but only http.ResponseWriter, so i hijack it.

...
webConn, webBuf, err := hj.Hijack()
if err != nil {
    // handle error
}
defer webConn.Close()

// Write resp
resp.Write(webBuf)
...

Write raw request

But When i hijack, http connection can't reuse (keep-alive), so it slow.

How to solve?

Thanks! Sorry for my pool English.

update 12/9
about http hijacking and keep-alive
about http hijacking and keep-alive
keep-alive, It keep two tcp connection, and can reuse.

about http hijacking and keep-alive
about http hijacking and keep-alive
but when i hijack, and conn.Close(), It can't reuse old connection, so it create a new tcp connection when i each refresh.

答案1

得分: 5

不要使用劫持,因为一旦劫持,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 {
        // 处理错误
    }
    copyResponse(resp, w)
}
英文:

Do not use hijack, Because once hijack, the HTTP server library will not do anything else with the connection, So can't reuse.

I change way, copy Header and Body, look like reverse proxy (http://golang.org/src/pkg/net/http/httputil/reverseproxy.go), Is works.

Example:

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)
}

答案2

得分: 0

似乎一旦连接关闭,keep-alive连接也会关闭。

一种可能的解决方案是在期望之前阻止连接关闭,但我不确定这是否是一个好建议。

也许正确的解决方案是创建一个net.TCPConn的实例,将连接复制到其中,然后调用.SetKeepAlive(true)

在运行下面的示例之前,请在另一个终端中使用netstat -antc | grep 9090命令启动。

示例中的路由:

localhost:9090/ok是一个基本的(非劫持)连接<br>
localhost:9090是一个持续10秒的劫持连接<br>

示例

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("Listening to localhost:9090")
    http.ListenAndServe(":9090", nil)
}

相关问题:http://code.google.com/p/go/issues/detail?id=5645

英文:

It seem that once the connection is closed the keep-alive connection closes as well.
One possible solution would be to prevent the connection from closing until desired, but I'm not sure if that good advise.

Maybe the correct solution involves creating a instance of net.TCPConn, copying the connection over it, then calling .SetKeepAlive(true).

Before running the below example, launch another terminal with netstat -antc | grep 9090.

Routes in example:

localhost:9090/ok is a basic (non-hijacked) connection<br>
localhost:9090 is a hijacked connection, lasting for 10 seconds.<br>

Example

package main

import (
    &quot;fmt&quot;
    &quot;net/http&quot;
    &quot;sync&quot;
    &quot;time&quot;
)

func checkError(e error) {
    if e != nil {
	    panic(e)
    }
}

var ka_seconds = 10
var conn_id = 0
func main() {
    http.HandleFunc(&quot;/ok&quot;, func(w http.ResponseWriter, r *http.Request) {
	    fmt.Fprintln(w, &quot;ok&quot;)
    })
    http.HandleFunc(&quot;/&quot;, func(w http.ResponseWriter, r *http.Request) {
	    conn_id++
	    fmt.Printf(&quot;Connection %v: Keep-alive is enabled %v seconds\n&quot;, conn_id, ka_seconds)
	    hj, ok := w.(http.Hijacker)
	    if !ok {
		    http.Error(w, &quot;webserver doesn&#39;t support hijacking&quot;, http.StatusInternalServerError)
		    return
	    }
	    conn, bufrw, err := hj.Hijack()
	    if err != nil {
		    http.Error(w, err.Error(), http.StatusInternalServerError)
		    return
	    }
	    // Don&#39;t forget to close the connection:
	    time.AfterFunc(time.Second* time.Duration(ka_seconds), func() {
		    conn.Close()
		    fmt.Printf(&quot;Connection %v: Keep-alive is disabled.\n&quot;, conn_id)
	    })
	    resp, err := http.Get(&quot;http://www.example.com&quot;)
	    checkError(err)
	    resp.Write(bufrw)
	    bufrw.Flush()
    })
    fmt.Println(&quot;Listing to localhost:9090&quot;)
    http.ListenAndServe(&quot;:9090&quot;, nil)
}

Related issue: http://code.google.com/p/go/issues/detail?id=5645

huangapple
  • 本文由 发表于 2013年12月5日 14:36:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/20393147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定