43

Go で単純な Web アプリを作成していて、応答をクライアントにストリーミングする必要があります (つまり、要求が完全に処理されると、バッファリングされず、ブロックで送信されます):

func handle(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "sending first line of data")
  sleep(10) //not real code
  fmt.Fprintf(res, "sending second line of data")
}

クライアントの観点からは、2 つの回線が同時に送信されます。どんな提案でも大歓迎です:)

@dystroyの回答後に編集

個人的に書き込みを行うたびにフラッシュすることは可能ですが、私のユースケースでは十分ではありません:

cmd := exec.Command("a long command that outputs lots of lines")
cmd.Stdout = res //where res is a http.ResponseWritter
cmd.Stderr = res
err := cmd.Run()

私の出力cmdもフラッシュしたい。とにかく ResponseWritter を「自動フラッシュ」するには?

解決

golang のメーリング リストでヘルプを見つけました。これを実現するには 2 つの方法があります。HTTP の基礎となる TCP 接続を引き継ぐことを許可するハイジャッカーを使用するか、書き込みとフラッシュを行う go ルーチンでコマンドの stdout と stderr をパイプします。

pipeReader, pipeWriter := io.Pipe()
cmd.Stdout = pipeWriter
cmd.Stderr = pipeWriter
go writeCmdOutput(res, pipeReader)
err := cmd.Run()
pipeWriter.Close()

//---------------------
func writeCmdOutput(res http.ResponseWriter, pipeReader *io.PipeReader) {
  buffer := make([]byte, BUF_LEN)
  for {
    n, err := pipeReader.Read(buffer)
    if err != nil {
      pipeReader.Close()
      break
    }

    data := buffer[0:n]
    res.Write(data)
    if f, ok := res.(http.Flusher); ok {
      f.Flush()
    }
    //reset buffer
    for i := 0; i < n; i++ {
      buffer[i] = 0
    }
  } 
}

最後の更新

さらに良い: http://play.golang.org/p/PpbPyXbtEs

4

2 に答える 2

1

私があなたの質問を誤解していたら申し訳ありませんが、以下のようなものがうまくいきますか?

package main

import (
    "bytes"
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    body := make([]byte, int(r.ContentLength))
    b := bytes.NewBuffer(body)
    if _, err := b.ReadFrom(r.Body); err != nil {
        fmt.Fprintf(w, "%s", err)
    }
    if _, err := b.WriteTo(w); err != nil {
        fmt.Fprintf(w, "%s", err)
    }
}

func main() {
    http.HandleFunc("/", handler)
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

$ curl --data "param1=value1&param2=value2" http://localhost:8080

戻り値:

param1=値1¶m2=値2

必要なデータをいつでも追加しbodyたり、別の場所からバッファにさらにバイトを読み取ったりしてから、すべてを再度書き込むことができます。

于 2013-10-10T13:01:46.877 に答える