2017-03-29 2 views
5

Ich möchte den Benutzer informieren, wenn eine HTTP-Anfrage fehlschlägt, ohne für jede HTTP-Anfrage zusätzlichen Code schreiben zu müssen.Zentrale Behandlung von HTTP-Fehlern in Angular 4

@Injectable() 
export class MyErrorHandler extends ErrorHandler { 

    constructor() { 
    super(false); 
    } 

    handleError(error: any) { 
    this.tellUser(error); 
    super.handleError(error); 
    } 

    tellUser(error: any) { 
    // dig for the root cause 
    if (error.rejection) { 
     error = error.rejection; 
    } 
    if (error instanceof ViewWrappedError) { 
     error = error.originalError; 
    } 

    let message; 
    if (error instanceof Response) { 
     // TODO: localize and display nicely 
     const messages = { 
     0: "Could not connect to server", 
     } 
     message = messages[error.status] || ("The server reported a system error (HTTP " + error.status + ")"); 
    } else { 
     message = "A system error occurred."; 
    } 
    console.warn(message); 
    } 
} 

aber die ViewWrappedError wurde in Angular 4 von

export function viewWrappedDebugError(err: any, context: DebugContext): Error { 
    if (!(err instanceof Error)) { 
    // errors that are not Error instances don't have a stack, 
    // so it is ok to wrap them into a new Error object... 
    err = new Error(err.toString()); 
    } 
    _addDebugContext(err, context); 
    return err; 
} 

, die aufgrund von Aufrufen toString auf der Httpresponse, macht es ersetzt:

ich für Winkel 2 einen funktionierenden Prototyp hatte schwer, den Statuscode abzufragen ...

Ich hätte angular erwartet, um eine öffentliche, gut unterstützte API für zentralisierte Fehlerbehandlung zur Verfügung zu stellen. Gibt es wirklich keine Möglichkeit, HTTP-Fehler außer der Analyse von Fehlermeldungen zentral zu behandeln?

Update: Ich würde bevorzugen, wenn eine Komponente die zentrale Fehlerbehandlung leicht außer Kraft setzen könnte.

Antwort

0

Ich zentralisiere diese Art von Logik in einem BaseService, und erben dann jeden Dienst von It. Angular 2 bietet keine Http Interceptors wie die vorherige Version, wodurch diese Art von Sachen schwierig zu handhaben ist.

import { Injectable } from '@angular/core'; 
import { Response } from '@angular/http'; 
import { Observable } from 'rxjs/Observable'; 
import { NotificationService } from '********'; 


@Injectable() 
export class BaseService { 
    protected url: string; 
    protected http: Http; 

    constructor(http: Http, protected notification: NotificationService) { 
    this.http = http; 
    } 

    protected extractData(res: Response) { 
     // 
     // Depende do formato da response, algumas APIs retornam um objeto data e dentro deste o conteudo propriamente dito 
     // Em minhas APIs sempre retorno diretamente o objeto que desejo 
     // 
     return res.json(); 
    } 

    protected handleError(error: Response | any) { 
    let erros: string[] = []; 

    switch (error.status) { 
     case 400: 
     let res = error.json(); 

    // 
    // Depende do formato, minhas APIs sempre retornar um objeto com array errors quando tenho 400 
    // 
     for (let index = 0; index < res.errors.length; index++) { 
      let msg = res.errors[index]; 
      erros.push(msg); 
     }; 

     this.notification.showMultipleWarn(erros); 
     break; 
     case 404: 
    this.notification.showWarning('O recurso requisitado não existe.'); 
    break; 
     case 406: 
     case 409: 
     case 500: 
     this.notification.showError('Ocorreu um erro inesperado.'); 
     break; 
     default: 
     this.notification.showError('Ocorreu um erro inesperado.'); 
     break; 
    } 

    return Observable.throw(new Error(error.status)); 
    } 
} 

Hier ist mein Blog-Post in gewisser Weise erklären dies weniger verbosely zu handhaben: Receitas Angular2: Interceptando erros HTTP de forma Global

Die Stelle ist auf Portugiesisch geschrieben, aber der Code könnte Ihnen einige Hinweise geben. Ich benutze diesen Ansatz gerade in einigen riesigen Projekten und es funktioniert gut.

1

Eine andere Option ist einfach, einen Dienst zu haben, der an den HTTP-Dienst delegiert, während Sie benutzerdefinierte Fehlerbehandlung, Debuglogik, zusätzliche Header usw. hinzufügen, die Sie mit Ihrer API interagieren müssen.

Dieser Service wird dann zu Ihrem zentralisierten Punkt für die Interaktion mit allem, was mit Http zu tun hat, und Sie können Ihre Fehlerbehandlung genau dort zentralisieren. In jedem Projekt, das ich entwickle, erstelle ich IMMER eine solche Klasse, weil praktisch jede einzelne API, mit der Sie interagieren, eine gemeinsame Konfiguration hat, die bei jeder Anfrage passieren muss (selbst wenn diese Konfiguration nur die zu verwendende Basis-URL angibt).

Beispiel für eine solche Klasse:

export class ApiGateway { 

    baseURL = "https://myapi.com"; // or sometimes pulled from another file 
    constructor(private http: Http) { } 

    get(path, params) { 
    showLoadingIndicator(); 

    let headers = this.createMySpecialHeaders(); 
    let options = { headers: headers } // and whatever else you need to generalize 
    let fullUrl = this.baseUrl + path + '?' + this.urlEncode(params)`; 
    return this.get(path, params, options) 
       .do(() => hideLoadingIndicator()) 
       .map(res => res.json()) 
       .catch(err => { 
        hideLoadingIndicator(); 
        // show error message or whatever the app does with API errors etc 
        // sometimes rethrow the error, depending on the use case 
       }) 
    } 
} 

Für mich ist das grundlegende OOP-Prinzipien - Sie Ihre Interaktionen mit Dingen außerhalb Ihrer Kontrolle in einer Adapterklasse wickeln Sie einen gewissen Schutz gegen externe Veränderungen zu ermöglichen und die API dieser externen Sache bei Bedarf auf etwas zu ändern, das Sie bevorzugen.

Wenn eine solche Klasse vorhanden ist, wenn Sie z. B. auf Angular 4 aktualisiert haben und sich die Mittel zum Empfangen von Fehlern ändern, haben Sie nur einen Platz zum Ändern der neuen Fehlertechnik.