我试图在角度为2 / RxJs的app中显示服务器发送的事件发射值。
后端通过服务器发送的事件定期向客户端发送单个字符串。
我不确定如何处理角度2 / RxJs侧的检索值。
这是我的客户(ng组件):
import {Component, OnInit} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
@Component({
selector: 'my-app',
template: `<h1>My second Angular 2 App</h1>
<ul>
<li *ngFor="#s of someStrings | async">
a string: {{ s }}
</li>
</ul>
`
})
export class AppComponent implements OnInit {
constructor(private http:Http) {
}
errorMessage:string;
someStrings:string[];
ngOnInit() {
this.getSomeStrings()
.subscribe(
aString => this.someStrings.push(aString),
error => this.errorMessage = <any>error);
}
private getSomeStrings():Observable<string> {
return this.http.get('interval-sse-observable')
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res:Response) {
if (res.status < 200 || res.status >= 300) {
throw new Error('Bad response status: ' + res.status);
}
let body = res.json();
return body || {};
}
private handleError(error:any) {
// In a real world app, we might send the error to remote logging infrastructure
let errMsg = error.message || 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
}
后端方法如下(并使用RxJava):
@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET, path = "interval-sse-observable")
public SseEmitter tickSseObservable() {
return RxResponse.sse(
Observable.interval(5, TimeUnit.SECONDS, Schedulers.io())
.map(tick -> randomUUID().toString())
);
}
我刚注意到应用程序挂起了请求,并且页面上没有显示任何内容。
我怀疑使用地图方法存在问题,即.map(this.extractData)
。
我只想将传入的字符串添加到数组中,并在模板中显示该数组,该数组会随着字符串的进入而更新。
有人可以帮忙吗?
编辑:这是一个有效的解决方案(感谢Thierry在下面的回答):
import {Component, OnInit} from 'angular2/core';
import 'rxjs/Rx';
@Component({
selector: 'my-app',
template: `<h1>My second Angular 2 App</h1>
<ul>
<li *ngFor="#s of someStrings">
a string: {{ s }}
</li>
</ul>
`
})
export class AppComponent implements OnInit {
someStrings:string[] = [];
ngOnInit() {
let source = new EventSource('/interval-sse-observable');
source.addEventListener('message', aString => this.someStrings.push(aString.data), false);
}
}
答案 0 :(得分:17)
这是一个有效的例子:
<强> SseService 强>
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs/Observable';
declare var EventSource;
@Injectable()
export class SseService {
constructor() {
}
observeMessages(sseUrl: string): Observable<string> {
return new Observable<string>(obs => {
const es = new EventSource(sseUrl);
es.addEventListener('message', (evt) => {
console.log(evt.data);
obs.next(evt.data);
});
return () => es.close();
});
}
}
<强> AppComponent 强>
import {Component, OnDestroy, OnInit} from '@angular/core';
import {SseService} from './shared/services/sse/sse.service';
import {Observable, Subscription} from 'rxjs/Rx';
@Component({
selector: 'my-app',
template: `<h1>Angular Server-Sent Events</h1>
<ul>
<li *ngFor="let message of messages">
{{ message }}
</li>
</ul>
`
})
export class AppComponent implements OnInit, OnDestroy {
private sseStream: Subscription;
messages:Array<string> = [];
constructor(private sseService: SseService){
}
ngOnInit() {
this.sseStream = this.sseService.observeMessages('https://server.com/mysse')
.subscribe(message => {
messages.push(message);
});
}
ngOnDestroy() {
if (this.sseStream) {
this.sseStream.unsubscribe();
}
}
}
答案 1 :(得分:7)
你不能使用Angular2的Http类来处理服务器端事件,因为它基于XHR对象。
您可以利用EventSource对象:
var source = new EventSource('/...');
source.addListener('message', (event) => {
(...)
});
参见这些文章:
答案 2 :(得分:0)
要添加到Thierry's answer,默认情况下,事件类型为&#39; message&#39;。但是,基于服务器端实现,事件类型可以是(&#39; chat&#39;,&#39; log&#39;等)。 就我而言,来自服务器的前两个事件是&#39; message&#39;其余的都是“记录”。我的代码如下所示
var source = new EventSource('/...');
source.addListener('message', message => {
(...)
});
source.addListener('log', log => {
(...)
});