简体   繁体   English

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

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

In one of my API's I mostly return a result (let's say paged 50 results) as one whole in an json array like so:在我的一个 API 中,我主要在json数组中作为一个整体返回一个结果(假设分页 50 个结果),如下所示:

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

I was wondering if there are better ways of doing this over HTTP2 (as it has many new partial streaming features) with Go's HTTP server (using HTTPS in Gin for this project).我想知道是否有更好的方法通过 HTTP2(因为它有许多新的部分流功能)使用 Go 的 HTTP 服务器(在这个项目中使用 Gin 中的 HTTPS)。

Maybe I could chunk every {} result and send them as segments on a stream?也许我可以将每个{}结果分块并将它们作为段发送到 stream 上? How would the AJAX call in Angular or jQuery know that there's a new chunk delivered (newline or some character marker?)? AJAX 在 Angular 或 jQuery 中的调用如何知道传递了一个新块(换行符或某些字符标记?)? And what call in the library could actually handle such a multi-promise (does that even exist? :P)?库中的什么调用实际上可以处理这样的多重承诺(甚至存在吗?:P)? Could I benefit from the HTTP2 stream-features in some way to prevent multiple-connections from opening?我能否以某种方式从 HTTP2 流功能中受益,以防止打开多个连接?

I'm kind of aiming to have the results nicely plop into the list as they come in.我的目标是让结果在出现时很好进入列表。

UPDATE更新

Maybe it's easier to use Keep-Alive header in some way to let's keep the connection open for for a certain amount of seconds to be able to stream over and fire many smaller requests/responses?也许以某种方式使用Keep-Alive header 更容易让我们保持连接打开一定的秒数,以便能够 stream 并触发许多较小的请求/响应?

As I see, application/x-ndjson could help you.如我所见, application/x-ndjson可以帮助您。

Here're an example that uses standard net/http package. You could port to GIN also.这是一个使用标准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)
    }
}

And simple JS:和简单的 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();
  }
}

Lookup Server Sent Events.查找服务器发送的事件。 It's essentially chunked response for which the browser already has built-in support.它本质上是浏览器已经内置支持的分块响应。

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

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