首頁 >後端開發 >Golang >如何在 Golang 中傳輸回應並克服'http.ResponseWriter”緩衝限制?

如何在 Golang 中傳輸回應並克服'http.ResponseWriter”緩衝限制?

Patricia Arquette
Patricia Arquette原創
2024-12-20 06:40:18293瀏覽

How to Stream Responses in Golang and Overcome `http.ResponseWriter` Buffering Limitations?

Golang 中的串流回應:緩衝的ResponseWriter 掛鉤

在Golang 中建立Web 應用程式時,了解http.http 的行為至關重要。響應作家。預設情況下,回應是緩衝的,這意味著一旦請求被完全處理,資料就會被收集並以區塊的形式發送。但是,在您想要逐行將回應串流傳輸到用戶端或處理超出緩衝容量的大型輸出的情況下,此行為會成為障礙。

請考慮以下範例:

func handle(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "sending first line of data")
  sleep(10) // Simulation of a long-running process
  fmt.Fprintf(res, "sending second line of data")
}

從客戶端的角度來看,「發送第一行資料」和「發送第二行資料」訊息應該分開接收。然而,由於緩衝,兩行將被聚合並同時發送。

要解決此問題,可以在每次寫入操作後手動刷新 ResponseWriter。這可以使用 Flusher 介面來實現,如下所示:

func handle(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "sending first line of data")
  if f, ok := res.(http.Flusher); ok {
    f.Flush()
  }
  sleep(10) // Simulation of a long-running process
  fmt.Fprintf(res, "sending second line of data")
}

透過此修改,回應將根據需要逐步串流傳輸到客戶端。

進階場景:管道外部命令

但是,在某些情況下,手動刷新可能不夠。考慮這樣一個場景:您想要將外部命令的輸出透過管道傳輸到客戶端。該命令產生大量數據,超出了緩衝能力。

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

// Function to write command output to ResponseWriter
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
    }
  }
}

在這種情況下,有必要「自動刷新」ResponseWriter 以確保資料無延遲地串流傳輸到客戶端。這可以使用提供的程式碼片段來實現。

替代解決方案

作為直接管道傳輸外部命令輸出的替代方法,可以使用基於通道的方法:

// Create a channel to communicate with the goroutine
outputChan := make(chan string)

// Start a goroutine to process the command output
go func() {
  scanner := bufio.NewScanner(cmd.Stdout)
  for scanner.Scan() {
    outputChan <- scanner.Text()
  }
  if err := scanner.Err(); err != nil {
    log.Fatal(err)
  }
  close(outputChan) // Notify that all output has been processed
}()

// Stream output to ResponseWriter lazily
func handleCmdOutput(res http.ResponseWriter, req *http.Request) {
  if f, ok := res.(http.Flusher); ok {
    for {
      select {
      case output := <-outputChan:
        res.Write([]byte(output + "\n"))
        f.Flush()
      default:
        time.Sleep(10 * time.Millisecond)
      }
    }
  }
}

在這種方法中,goroutine 非同步處理命令輸出並將其傳送到通道。然後,handleCmdOutput 函數將輸出惰性地流式傳輸到 ResponseWriter,在每次寫入作業後刷新。

透過利用 Flusher 介面並探索替代方法,您可以有效地將資料串流傳輸到客戶端並克服 Golang ResponseWriter 中的緩衝限制。

以上是如何在 Golang 中傳輸回應並克服'http.ResponseWriter”緩衝限制?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn