什么是适合使用异步数据流的 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 - 但看起来这在这里可能不是问题。
我是响应式编程的新手。我的应用程序使用 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 - 但看起来这在这里可能不是问题。