我们可以很简单实现HTTP流式数据返回。

框架版本 < v2.4

如果当前使用的框架版本小于 v2.4 正式版(不是 beta 版本),使用以下方式返回(标准库原生写法)。

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. "github.com/gogf/gf/v2/frame/g"
  7. "github.com/gogf/gf/v2/net/ghttp"
  8. )
  9. func main() {
  10. s := g.Server()
  11. s.BindHandler("/", func(r *ghttp.Request) {
  12. rw := r.Response.RawWriter()
  13. flusher, ok := rw.(http.Flusher)
  14. if !ok {
  15. http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
  16. return
  17. }
  18. r.Response.Header().Set("Content-Type", "text/event-stream")
  19. r.Response.Header().Set("Cache-Control", "no-cache")
  20. r.Response.Header().Set("Connection", "keep-alive")
  21. for i := 0; i < 100; i++ {
  22. _, err := fmt.Fprintf(rw, "data: %d\n", i)
  23. if err != nil {
  24. panic(err)
  25. }
  26. flusher.Flush()
  27. time.Sleep(time.Millisecond * 200)
  28. }
  29. })
  30. s.SetPort(8999)
  31. s.Run()
  32. }

框架版本 >= v2.4

由于以上操作有点繁琐,因此在该版本以后做了一些操作上的改进,如果当前使用的框架版本在 v2.4 正式版(不是 beta 版本)以上,那么可以使用以下方式快速实现流式数据返回。

  1. package main
  2. import (
  3. "time"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/net/ghttp"
  6. )
  7. func main() {
  8. s := g.Server()
  9. s.BindHandler("/", func(r *ghttp.Request) {
  10. r.Response.Header().Set("Content-Type", "text/event-stream")
  11. r.Response.Header().Set("Cache-Control", "no-cache")
  12. r.Response.Header().Set("Connection", "keep-alive")
  13. for i := 0; i < 100; i++ {
  14. r.Response.Writefln("data: %d", i)
  15. r.Response.Flush()
  16. time.Sleep(time.Millisecond * 200)
  17. }
  18. })
  19. s.SetPort(8999)
  20. s.Run()
  21. }

示例结果

执行后访问 http://127.0.0.1:8999/ 可以看到数据通过流式方式不断地将数据返回给调用端。

数据返回-Stream返回 - 图1

注意事项

  • 如果是在控制器中使用, Request 对象的获取可以通过 g.RequestFromCtx(ctx) 方法。
  • 如果有前置统一输入输出处理的中间件,请将该方法放置于中间件作用域之外,或者使用 r.ExitAll() 方法跳出中间件控制。

资料

Server-Sent Events (SSE)