2016-02-10 14 views
78

parte del mio codice: Come rilevare l'eccezione correttamente da http.request()?

import {Injectable} from 'angular2/core'; 
import {Http, Headers, Request, Response} from 'angular2/http'; 
import {Observable} from 'rxjs/Observable'; 
import 'rxjs/add/operator/map'; 

@Injectable() 
export class myClass { 

    constructor(protected http: Http) {} 

    public myMethod() { 
    let request = new Request({ 
     method: "GET", 
     url: "http://my_url" 
    }); 

    return this.http.request(request) 
     .map(res => res.json()) 
     .catch(this.handleError); // Trouble line. 
           // Without this line code works perfectly. 
    } 

    public handleError(error: Response) { 
    console.error(error); 
    return Observable.throw(error.json().error || 'Server error'); 
    } 

} 

myMethod() produce un'eccezione in console del navigatore:

ORIGINAL EXCEPTION: TypeError: this.http.request(...).map(...).catch is not a function

+0

[Ecco il metodo consigliato ufficiale] (https://angular.io/docs/ts/latest/guide/server-communication.html#!#error-handling) per gestire le eccezioni sulle richieste HTTP da _Angular.io_ . C'è un collegamento a un [esempio dal vivo] (https://embed.plnkr.co/?show=preview) su Plunker nella parte inferiore della pagina (vai a '/ app/toh/hero.service.ts' per vedere il codice del servizio client HTTP). –

risposta

138

forse si può provare ad aggiungere questo nelle vostre importazioni:

import 'rxjs/add/operator/catch'; 

È può anche fare:

return this.http.request(request) 
    .map(res => res.json()) 
    .subscribe(
    data => console.log(data), 
    err => console.log(err), 
    () => console.log('yay') 
); 

Per commenti:

EXCEPTION: TypeError: Observable_1.Observable.throw is not a function

Allo stesso modo, per questo, è possibile utilizzare:

import 'rxjs/add/observable/throw'; 
+1

Grazie per l'aiuto, funziona. Dopo di che ho lo stesso problema con la funzione 'throw()'. Ho aggiunto questa riga 'import 'rxjs/Rx';' invece. Ora tutti gli operatori funzionano correttamente. – mnv

+0

Hai simulato un errore per vedere se il '.catch' funziona davvero? Quel '.subscribe()' funziona di sicuro. – acdcjunior

+1

Sì, il secondo problema era 'ECCEZIONE: TypeError: Observable_1.Observable.throw non è una funzione'. Può essere risolto con @MattScarpino answer o in maner da questo plunker come ho detto sopra: https://angular.io/resources/live-examples/server-communication/ts/plnkr.html – mnv

1

Le funzioni RxJS devono essere specificamente importato. Un modo semplice per farlo è importare tutte le sue funzioni con import * as Rx from "rxjs/Rx"

Quindi assicurarsi di accedere alla classe Observable come Rx.Observable.

+0

Grazie! È una buona soluzione per il secondo problema di questo script. – mnv

+10

Rxjs è un file molto grande, se si importano tutte le funzionalità si aumenterà il tempo di caricamento –

+0

Non si dovrebbe semplicemente importare tutto da Rxjs se sono necessari solo uno o due operatori. –

54

Nuovo servizio aggiornato per utilizzare il HttpClientModule e RxJS v5.5.x:

import { Injectable }     from '@angular/core'; 
import { HttpClient, HttpErrorResponse } from '@angular/common/http'; 
import { Observable }     from 'rxjs/Observable'; 
import { catchError, tap }    from 'rxjs/operators'; 
import { SomeClassOrInterface}   from './interfaces'; 
import 'rxjs/add/observable/throw'; 

@Injectable() 
export class MyService { 
    url = 'http://my_url'; 
    constructor(private _http:HttpClient) {} 
    private handleError(operation: String) { 
     return (err: any) => { 
      let errMsg = `error in ${operation}() retrieving ${this.url}`; 
      console.log(`${errMsg}:`, err) 
      if(err instanceof HttpErrorResponse) { 
       // you could extract more info about the error if you want, e.g.: 
       console.log(`status: ${err.status}, ${err.statusText}`); 
       // errMsg = ... 
      } 
      return Observable.throw(errMsg); 
     } 
    } 
    // public API 
    public getData() : Observable<SomeClassOrInterface> { 
     // HttpClient.get() returns the body of the response as an untyped JSON object. 
     // We specify the type as SomeClassOrInterfaceto get a typed result. 
     return this._http.get<SomeClassOrInterface>(this.url) 
      .pipe(
       tap(data => console.log('server data:', data)), 
       catchError(this.handleError('getData')) 
      ); 
    } 

Vecchio servizio, che utilizza il HttpModule deprecato:

import {Injectable}    from 'angular2/core'; 
import {Http, Response, Request} from 'angular2/http'; 
import {Observable}    from 'rxjs/Observable'; 
import 'rxjs/add/observable/throw'; 
//import 'rxjs/Rx'; // use this line if you want to be lazy, otherwise: 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/do'; // debug 
import 'rxjs/add/operator/catch'; 

@Injectable() 
export class MyService { 
    constructor(private _http:Http) {} 
    private _serverError(err: any) { 
     console.log('sever error:', err); // debug 
     if(err instanceof Response) { 
      return Observable.throw(err.json().error || 'backend server error'); 
      // if you're using lite-server, use the following line 
      // instead of the line above: 
      //return Observable.throw(err.text() || 'backend server error'); 
     } 
     return Observable.throw(err || 'backend server error'); 
    } 
    private _request = new Request({ 
     method: "GET", 
     // change url to "./data/data.junk" to generate an error 
     url: "./data/data.json" 
    }); 
    // public API 
    public getData() { 
     return this._http.request(this._request) 
      // modify file data.json to contain invalid JSON to have .json() raise an error 
      .map(res => res.json()) // could raise an error if invalid JSON 
      .do(data => console.log('server data:', data)) // debug 
      .catch(this._serverError); 
    } 
} 

Io uso .do() (now .tap()) per il debug.

Quando si verifica un errore del server, il body dell'oggetto Response ricevo dal server che sto utilizzando (lite-server) contiene solo testo, quindi il motivo che uso err.text() sopra piuttosto che err.json().error. Potrebbe essere necessario regolare quella linea per il tuo server.

Se res.json() solleva un errore perché non in grado di analizzare i dati JSON, _serverError non otterrà un oggetto Response, quindi il motivo del controllo instanceof.

In questo plunker, cambiare url a ./data/data.junk per generare un errore.


Gli utenti di entrambi i servizi devono avere il codice in grado di gestire l'errore:

@Component({ 
    selector: 'my-app', 
    template: '<div>{{data}}</div> 
     <div>{{errorMsg}}</div>` 
}) 
export class AppComponent { 
    errorMsg: string; 
    constructor(private _myService: MyService) {} 
    ngOnInit() { 
     this._myService.getData() 
      .subscribe(
       data => this.data = data, 
       err => this.errorMsg = <any>err 
      ); 
    } 
} 
2

nella versione più recente di angular4 uso

import { Observable } from 'rxjs/Rx' 

sarà importare tutte le cose necessarie.

+4

Non farlo, importa tutto Rxjs. –