ウェブサイト検索

typescript - 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() が例外を発生させます:

元の例外: TypeError: this.http.request(...).map(...).catch は関数ではありません

回答 #1

おそらく、あなたのインポートにこれを追加してみることができます:

import 'rxjs/add/operator/catch';

あなたは次のこともできます:

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

コメントによると:

例外: TypeError: Observable_1.Observable.throw は関数ではありません

同様に、それについては、次のものを使用できます:

import 'rxjs/add/observable/throw';

回答 #2

新しいサービスが HttpClientModule と 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'))
            );
    }

非推奨の HttpModule を使用する旧サービス:

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);
    }
}

デバッグのために .do()(現在は .tap())を使います。

サーバーエラーが発生した場合、私が使用しているサーバー(lite-server)から取得する Response オブジェクトの body には単なるテキストしか含まれていません。したがって、上記では err.json().error ではなく err.text() を使用しています。その行は、ご使用のサーバーに合わせて調整する必要があるかもしれません。

もし res.json() が JSON データを解析できずにエラーを発生させた場合、_serverError は Response オブジェクトを受け取らないため、instanceof チェックが行われる理由となります。

このplunkerでは、エラーを発生させるためにurlを./data/data.junkに変更してください。

どちらのサービスのユーザーも、次のエラーを処理できるコードを持っているべきです:

@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
            );
    }
}

関連記事