最佳媒体类型,通过服务器发送事件向 Angular/RxJs/观察者返回 Flux



上下文:一个Spring Web Flux,在服务器发送事件样式中将Flux返回到Angular。

个人知识:

根据其他堆栈溢出主题

媒体类型 applicationjson 将缓冲内存中的 Flux 和 一次性序列化它。

媒体类型 applicationstream+json 将在网络上刷新 Flux 的每个元素 输入。当流是无限的或当您需要时,此行为很方便 在信息可用时立即将其推送到客户端。

基于前面的两个前提,我选择 applicationstream+json 是因为我想"在信息可用时立即将信息推送到客户端"而不是"缓冲内存中的 Flux 和 一次性序列化"。

好吧,如果我在下面的WebFlux端点中添加MediaType.APPLICATION_STREAM_JSON,那么从Spring Webclient读取时很好,但它不适用于通过SSE连接的Angular/RxJs

// Delay 0.5 second
@GetMapping(path = "/search-with-delay/{parte_da_palavra}")
public Flux<Sugestao> getSugestoesDelay(@PathVariable("parte_da_palavra") String parte_da_palavra) {
return sugestaoService.findAllMySugestoes("name", parte_da_palavra).delayElements(Duration.ofMillis(500));
}
@GetMapping(path = "/search/{parte_da_palavra}")
public Flux<Sugestao> getSugestoes(@PathVariable("parte_da_palavra") String parte_da_palavra) {
return sugestaoService.findAllMySugestoes("name", parte_da_palavra);
}

app.component.ts

import { Component, OnInit } from '@angular/core';
//SERVICES
import { SseService } from './sse.service';
import { NosseService } from './nosse.service';
//MODELS
import { Sugestao } from './sugestao';
//RXJS
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
sugestoes$: Observable<any>;
restItems: any;
//### SSE
searchSseWithDelay(searchValue: string): void {
this.sugestoes$ = this.sseService
.getServerSentEvent("http://localhost:8080/sugestao/search-with-delay/" + searchValue);
}
searchSseWithoutDelay(searchValue: string): void {
this.sugestoes$ = this.sseService
.getServerSentEvent("http://localhost:8080/sugestao/search/" + searchValue);
}
//### Without SSE
searchWithDelay(searchValue: string): void {
this.sugestoes$ = this.nosseService.getWithoutServerSentEvent("http://localhost:8080/sugestao/search-with-delay/" + searchValue);
}
searchWthoutDelay(searchValue: string): void {
this.sugestoes$ = this.nosseService.getWithoutServerSentEvent("http://localhost:8080/sugestao/search/" + searchValue);
}
constructor(
private sseService: SseService, private nosseService: NosseService) { }
ngOnInit() {
}

}

及其服务

没有上交所

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { Sugestao } from './sugestao';
import { HttpClient } from '@angular/common/http';
import { map, tap } from 'rxjs/operators';
@Injectable({
providedIn: "root"
})
export class NosseService {
constructor(private http: HttpClient) { }
getWithoutServerSentEvent(url: string): Observable<any> {
return this.http
.get<Sugestao[]>(url)
.pipe()
;
}
}

与上交所

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { Sugestao } from './sugestao';

@Injectable({
providedIn: "root"
})
export class SseService {
sugestoes: Sugestao[] = [];
constructor(private _zone: NgZone) { }
getServerSentEvent(url: string): Observable<any> {
this.sugestoes = [];
return Observable.create(observer => {
const eventSource = this.getEventSource(url);
eventSource.onmessage = event => {
this._zone.run(() => {
let json = JSON.parse(event.data);
this.sugestoes.push(new Sugestao(json['id'], json['name'], json['phone'], json['account']));
observer.next(this.sugestoes);
});
};
eventSource.onerror = (error) => {
if (eventSource.readyState === 0) {
console.log('The stream has been closed by the server.');
eventSource.close();
observer.complete();
} else {
observer.error('EventSource error: ' + error);
}
}
});
}
private getEventSource(url: string): EventSource {
return new EventSource(url);
}

}

谷歌搜索我发现基本上说我必须使用文本/事件流

"如果我们在不使用 Accept 标头或将其设置为 application/json 的情况下请求内容, 我们将获得一个同步的、JSON 格式的响应。 如果我们想在 Spring 中使用服务器发送的事件支持来实现我们的完整反应式堆栈, 我们在请求中(显式或在幕后(将 Accept 标头设置为文本/事件流, 因此激活了 Spring 中的反应功能"。

最后阅读了我在Mozila文档中找到的HTML5

"事件源实例打开与 HTTP 服务器的持久连接, 以文本/事件流格式发送事件。 连接将保持打开状态,直到通过调用 EventSource.close(( 关闭。

好吧,在那之后我真的很困惑。我肯定会使用Angular/RxJs/SSE,我的意思是,我根本不会在客户端使用Spring WebClient。据我所知,MediaType.APPLICATION_STREAM_JSON是我的业务需求中的最佳选择,但似乎因为我使用的是 SSE,所以我必须更喜欢MediaType.TEXT_EVENT_STREAM并且当尝试使用任何返回事件流的 MediaType 时,我习惯于编码观察器的方式不正确。

所以我的直接问题是:在我的端点中设置的最合适的 MediaType 是什么,它打算很快返回 Flux,数据可以使用 HTML 5 服务器发送事件功能提供给 Angular/RxJs/Oberver?

Spring 开发者声明:

"application/

stream+json"被弃用,取而代之的是"application/x-ndjson"。后者现在在杰克逊编码器和解码器中也开箱即用。虽然它不是正式注册的媒体类型,但至少它是一种常见的约定,似乎正在使用,而 JSON 行甚至没有。还有JSON文本序列,仍然可以使用换行符作为分隔符,但"application/json-seq"需要向杰克逊编码器和解码器注册。至于换行符以外的分隔符,我不确定杰克逊的非阻塞解析器是否支持这一点。

总之,使用行分隔的JSON,其中"application/x-ndjson"作为开箱即用的媒体类型支持,并用作"application/stream+json"的替代品。或者,注册任何其他 MIME 类型,只要它是行分隔的 JSON 格式,它就会工作相同。MIME 类型本身只是描述格式的约定,只要双方都理解它就足够了。

最新更新