Search code examples
gostreamgorilla

Gorilla mux streaming data to browser is not sending item one by one


I am trying to buffer data to browser. My intention is to send each item one by one with a delay of 1 second. However when I test in browser its just wait for all the delays to complete and show the result at once.

func StreamHandler(w http.ResponseWriter, r *http.Request) {
    log.Println("string handler invoked")
    flusher, _ := w.(http.Flusher)
    for i := 0; i < 15000; i++ {
        // w.Write([]byte("Gorilla! \n"))
        fmt.Println(i)
        fmt.Fprintf(w, "Gorilla! %v \n", i)
        flusher.Flush()
        time.Sleep(1 * time.Second)
        // time.Sleep(1 * time.Second)
    }
    fmt.Println("done")
}

Similar thing is super each to do with echo web framework. following example in echo framework makes browser to show data one by one

e.GET("/", func(c echo.Context) error {
        c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
        c.Response().WriteHeader(http.StatusOK)

        enc := json.NewEncoder(c.Response())
        for _, l := range locations {
            if err := enc.Encode(l); err != nil {
                return err
            }
            c.Response().Flush()
            time.Sleep(1 * time.Second)
        }
        return nil
    })

Please help me out to make it work in gorilla framework.


Solution

  • So following code works

    log.Println("string handler invoked")
        flusher, ok := w.(http.Flusher)
        if !ok {
            log.Println("responseWriter is not really a flusher")
            return
        }
        //this header had no effect
        w.Header().Set("Connection", "Keep-Alive")
        //these two headers are needed to get the http chunk incremently
        w.Header().Set("Transfer-Encoding", "chunked")
        w.Header().Set("X-Content-Type-Options", "nosniff")
        for i := 0; i < 20; i++ {
            // w.Write([]byte("Gorilla! \n"))
            fmt.Println(i)
            fmt.Fprintf(w, "Gorilla! %v \n", i)
            flusher.Flush()
            time.Sleep(1 * time.Second)
            // time.Sleep(1 * time.Second)
        }
        fmt.Println("done")