es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Usando HttpClient para crear una solicitud de EventStream

Utilicé el siguiente código para obtener un flujo de eventos del servidor:

getStream(): Observable<responsemodel> {
    return new Observable(obs => {
      const source = new EventSource(`http://backend/api/stream`);
      source.onmessage = (ev): void => this.zone.run(() => obs.next(JSON.parse(ev.data)));
      source.onerror = (err): void => this.zone.run(() => obs.error(err));
    });
}

… lo cual funciona como se esperaba. Pero ahora necesito tratar el EventStream de la misma manera en que se tratan otras solicitudes HTTP, lo cual hago con interceptores. Los interceptores no funcionan con EventSource.

Así que intenté algo como esto en su lugar:

constructor(
  private http: HttpClient,
  private zone: NgZone
) {}


getStream(): Observable<responsemodel> {
    return new Observable(obs => {
        const req = new HttpRequest('GET', `http://backend/api/stream`, {
          observe: 'body',
          headers: new HttpHeaders({
            Accept: 'text/event-stream',
            'Cache-Control': 'no-cache'
          })
        });
        const source = this.http.request<responsemodel>(req).subscribe(ev => this.zone.run(() => obs.next(ev)));
    });
}

Lo que parece ser el camino correcto, ya que la solicitud permanece pendiente en la pestaña de red de Chrome hasta que se dispara algo (aunque los datos están vacíos):

enter image description here

Entonces, ¿cómo puedo hacer eso?

Gracias

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    La API EventSource no es compatible con los interceptores, por lo que una solución sería utilizar HttpClient para realizar la solicitud y luego analizar manualmente el flujo de eventos. En el código anterior, el método getStream() utiliza HttpClient para enviar la solicitud GET y se suscribe al observable resultante para obtener los eventos. Sin embargo, la respuesta del servidor está en formato de flujo de eventos, que debe ser analizada manualmente para separar los eventos individuales.

    Aquí tienes una versión actualizada del código que muestra cómo hacer esto:

    getStream(): Observable<responsemodel> {
      return new Observable(observer => {
        const req = new HttpRequest('GET', `http://backend/api/stream`, {
          headers: new HttpHeaders({
            Accept: 'text/event-stream',
            'Cache-Control': 'no-cache'
          })
        });
        const source = this.http.request(req).subscribe(
          event => {
            if (event.type === HttpEventType.Response) {
              // analizar el flujo de eventos
              const parseStream = (data: string) => {
                const events = data.split('\n\n');
                events.slice(0, -1).forEach(eventData => {
                  observer.next(JSON.parse(eventData));
                });
              };
              parseStream(event.body);
            }
          },
          err => observer.error(err),
          () => observer.complete()
        );
        return () => {
          source.unsubscribe();
        };
      });
    }
    

    Aquí, la función parseStream se llama cada vez que HttpClient recibe una respuesta. La función divide los datos en eventos separados y luego los emite como elementos separados utilizando observer.next(). La API EventSource está buscando continuamente nuevos eventos, mientras que HttpClient solo envía la solicitud una vez. Por lo tanto, se invoca el método source.unsubscribe() cuando el suscriptor se desuscribe manualmente del observable.

Comments are closed.