Streaming-Antworten in Golang: Eine gepufferte ResponseWriter-Hitch
Beim Erstellen von Webanwendungen in Golang ist es wichtig, das Verhalten von http zu verstehen. ResponseWriter. Standardmäßig werden Antworten gepuffert, was bedeutet, dass Daten gesammelt und in Blöcken gesendet werden, sobald die Anfrage vollständig verarbeitet ist. In Szenarien, in denen Sie Antworten Zeile für Zeile an Clients streamen oder große Ausgaben verarbeiten möchten, die die Pufferkapazität überschreiten, wird dieses Verhalten jedoch zu einem Hindernis.
Betrachten Sie das folgende Beispiel:
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") }
Aus Sicht des Clients sollten die Nachrichten „Senden der ersten Datenzeile“ und „Senden der zweiten Datenzeile“ getrennt empfangen werden. Aufgrund der Pufferung werden jedoch beide Zeilen aggregiert und gleichzeitig gesendet.
Um dieses Problem zu beheben, kann man den ResponseWriter nach jedem Schreibvorgang manuell leeren. Dies kann mithilfe der Flusher-Schnittstelle erreicht werden, wie unten gezeigt:
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") }
Mit dieser Änderung wird die Antwort nach und nach nach Wunsch an den Client gestreamt.
Erweitertes Szenario : Externe Befehle weiterleiten
In bestimmten Situationen reicht die manuelle Spülung jedoch möglicherweise nicht aus. Stellen Sie sich ein Szenario vor, in dem Sie die Ausgabe eines externen Befehls an den Client weiterleiten möchten. Der Befehl generiert eine große Datenmenge, die die Pufferkapazität überschreitet.
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 } } }
In diesem Fall ist es notwendig, den ResponseWriter „automatisch zu leeren“, um sicherzustellen, dass die Daten ohne Verzögerung an den Client gestreamt werden. Dies kann mit dem bereitgestellten Code-Snippet erreicht werden.
Alternative Lösungen
Als Alternative zur direkten Weiterleitung der Ausgabe des externen Befehls kann man einen kanalbasierten Ansatz verwenden:
// 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) } } } }
Bei diesem Ansatz verarbeitet die Goroutine die Befehlsausgabe asynchron und sendet sie an den Kanal. Die Funktion „handleCmdOutput“ streamt die Ausgabe dann langsam an den ResponseWriter und leert sie nach jedem Schreibvorgang.
Durch die Nutzung der Flusher-Schnittstelle und die Erkundung alternativer Ansätze können Sie Daten effektiv an Clients streamen und die Pufferbeschränkung im ResponseWriter von Golang überwinden.
Das obige ist der detaillierte Inhalt vonWie streame ich Antworten in Golang und überwinde die Puffereinschränkungen von „http.ResponseWriter'?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!