Pregunta

I heard here that

once you write anything in the response, the request body will be closed which prevents you from reading anything from it

If that is true, how can I write a proper duplex handler that is able to read from the request body, make some kind of transformation, and then write to the response body, in a streaming fashion just like people do in node.js ?

¿Fue útil?

Solución

I ended up managing to do this with http.Hijacker.

After the request is made and the request headers are parsed, I can read from *http.Request.Body, then hijack the connection and write to it, at the same time, like this:

hj, ok := w.(http.Hijacker)
if !ok {
    http.Error(w, "hijacking not supported", 500)
    return
}

conn, bufrw, err := hj.Hijack()
if err != nil {
    http.Error(w, err.Error(), 500)
    return
}
defer conn.Close()

And then conn is a net.Conn which is the underlying TCP connection to the client, bufrw is a *bufio.ReadWriter, and to write the response without closing the body all I have to do is

_, err = bufrw.WriteString("HTTP/1.1 200 OK\n\n")
_, err = bufrw.WriteString("this")
_, err = bufrw.WriteString("is")
_, err = bufrw.WriteString("the")
_, err = bufrw.WriteString("response")
_, err = bufrw.WriteString("body")

And then I'm not sure about this but maybe someone can complete the answer, it's a good idea to flush the buffers down the connection once in a while with

err := bufrw.Flush()

Otros consejos

From the net/http docs you are referring to

var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")

ErrBodyReadAfterClose is returned when reading a Request or Response Body after the body has been closed. This typically happens when the body is read after an HTTP Handler calls WriteHeader or Write on its ResponseWriter

However I tried the code linked from the blog article you mentioned and it works fine under go 1.1.2 unless I write more than about 4k of data first in which case r.ParseForm() returns ErrBodyReadAfterClose.

So I think the answer is no, you can't do full duplex HTTP in go in general unless the responses are short (under 4k).

I would say that doing full duplex HTTP requests is unlikely to be a big benefit though as most clients won't attempt to read from the response until they have finished sending the request, so the most you'll win is the size of the TCP buffers in the client & server. A deadlock seems likely if these buffers are exceeded, eg

  • client is sending request
  • server is sending response
  • servers buffers get full sending response
  • server blocks
  • server no longer reading clients request
  • client buffers fill up
  • client blocks
  • deadlock
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top