繁体   English   中英

将 JSON 数据作为每个块的 stream 返回到 Angular2 或通过 HTTP2 (HTTPS) 返回 jQuery

[英]Returning JSON data as a stream per chunk to Angular2 or jQuery over HTTP2 (HTTPS)

在我的一个 API 中,我主要在json数组中作为一个整体返回一个结果(假设分页 50 个结果),如下所示:

[{},{},{},{},{},...]

我想知道是否有更好的方法通过 HTTP2(因为它有许多新的部分流功能)使用 Go 的 HTTP 服务器(在这个项目中使用 Gin 中的 HTTPS)。

也许我可以将每个{}结果分块并将它们作为段发送到 stream 上? AJAX 在 Angular 或 jQuery 中的调用如何知道传递了一个新块(换行符或某些字符标记?)? 库中的什么调用实际上可以处理这样的多重承诺(甚至存在吗?:P)? 我能否以某种方式从 HTTP2 流功能中受益,以防止打开多个连接?

我的目标是让结果在出现时很好进入列表。

更新

也许以某种方式使用Keep-Alive header 更容易让我们保持连接打开一定的秒数,以便能够 stream 并触发许多较小的请求/响应?

如我所见, application/x-ndjson可以帮助您。

这是一个使用标准net/http package 的示例。您也可以移植到 GIN。

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "time"
)

// let's generate some fake data
func sampleStream() <-chan []byte {
    out := make(chan []byte, 10)
    go func() {
        for i := 0; i < 10; i++ {
            d := map[string]interface{}{"hello": i}
            buf, _ := json.Marshal(d)
            out <- buf
            time.Sleep(200 * time.Millisecond)
        }
        close(out)
    }()
    return out
}

func streamJSON(w http.ResponseWriter, r *http.Request) {
    flusher, ok := w.(http.Flusher)
    if !ok {
        w.WriteHeader(500)
        w.Write([]byte("Server unsupport flush"))
        return
    }

    // proper handle cors !!!
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/x-ndjson")
    w.Header().Set("Connection", "Keep-Alive")
    w.Header().Set("X-Content-Type-Options", "nosniff")
    for buf := range sampleStream() {
        w.Write(buf)
        w.Write([]byte("\n"))
        flusher.Flush()
    }
}

func main() {
    http.HandleFunc("/", streamJSON)
    s := &http.Server{
        Addr: ":8080",
    }
    fmt.Println("Listen :8080")
    if err := s.ListenAndServe(); err != nil {
        panic(err)
    }
}

和简单的 JS:

const abortController = new AbortController();

async function main() {
  const res = await fetch("http://localhost:8080", {
    signal: abortController.signal,
  });
  const reader = res.body.getReader();
  const textDecoder = new TextDecoder();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        break;
      }
      const text = textDecoder.decode(value);
      const json = JSON.parse(text);
      console.log(json);
    }
  } finally {
    reader.releaseLock();
  }
}

查找服务器发送的事件。 它本质上是浏览器已经内置支持的分块响应。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM