什么是适合使用异步数据流的 http 内容类型?

What is the suitable http content-type for consuming an asynchronous stream of data?

我是响应式编程的新手。我的应用程序使用 Angular 和 Spring Webflux 的组合。

所以我有一个服务器端点,它产生 Json_values 的流,延迟 1 秒。[Spring - webflux]

@CrossOrigin 
@GetMapping(value = "/flux" , produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<ObjType> returnFlux()
{
    return Flux.just(Obj1, Obj2, Obj3,...)
        .delayElements(Duration.ofSeconds(1));
}

还有我的客户。 Angular 一旦数据块可用,Http 就会记录响应。 [Angular] 我的代码看起来像这样

public getResponse()
{
    var _reqOptionsArgs= { headers: new HttpHeaders().set( 'Content-Type', 'application/json' ) };

    var observable = this.httpClient.get<any>("http://localhost:8080/flux", _reqOptionsArgs);

    observable.subscribe(val => console.log(val),
                         err => console.error(err),
                         () => console.log('Observer got a complete notification'));
}

现在我希望我的方法在 flux 发出 json 对象后立即在控制台上记录它们。但是当 flux 发出 5 个值时,浏览器在等待 5 秒后抛出异常:

SyntaxError: Unexpected token { in JSON at position 8
    at JSON.parse (<anonymous>)
    at XMLHttpRequest.onLoad (http://localhost:4200/vendor.js:9848:51)
    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:3397:31)
    at Object.onInvokeTask (http://localhost:4200/vendor.js:71849:33)
    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:3396:60)
    at Zone.runTask (http://localhost:4200/polyfills.js:3174:47)
    at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:3471:34)
    at invokeTask (http://localhost:4200/polyfills.js:4609:14)
    at XMLHttpRequest.globalZoneAwareCallback (http://localhost:4200/polyfills.js:4646:21)

但是当我从浏览器触发 localhost:8080/flux 时,它会在对象发出后立即打印响应。

也许我在 angular 中为 httpClient 中的响应提供了错误的内容类型。 但与此同时,我很好奇浏览器如何响应那块数据。

当您的 JSON 无效时会出现此错误。尝试调试到达您客户端的 JSON 对象的结构。也尝试删除 http-headers 并让 angular http-client 自己处理它们

您遇到的特定错误是因为 Streaming JSON (application/stream+json) 和普通旧 JSON (application/json) 是两种不同的内容类型。 Streaming JSON 的不同之处在于它是由另一个值(通常是换行符)分隔的单个 JSON objects 的 collection,并且在本身,因此无效 JSON.

话虽如此,您将很难为此使用 HttpClient - 它旨在读取完整响应然后关闭,而您却向它发送 JSON 流. (本质上,它是错误的工具。)

您几乎肯定想使用 EventSource,类似于:

var es = new EventSource("http://localhost:8080/flux");
es.onmessage = function(e) {
    console.log(e.data);
}

然后您可以在 e.data 上致电 JSON.parse() 或类似电话,然后在那里做您想做的事。

这里唯一的缺点是 EventSource 不允许您在没有 polyfill 的情况下设置 HTTP headers - 但看起来这在这里可能不是问题。