Część mojego kodu:
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()
tworzy wyjątek w konsoli przeglądarki:
ORYGINALNY WYJĄTEK: TypeError: this.http.request (...). Map (...). Catch nie jest funkcją
throw()
funkcją.import 'rxjs/Rx';
Zamiast tego dodałem tę linię . Teraz wszystkie operatory działają poprawnie..catch
naprawdę działa? To.subscribe()
na pewno działa.EXCEPTION: TypeError: Observable_1.Observable.throw is not a function
. Można to naprawić za pomocą odpowiedzi @MattScarpino lub w inny sposób z tego plunkera, jak powiedziałem powyżej: angular.io/resources/live-examples/server-communication/ts/ ...import 'rxjs/add/observable/throw';
i nie importuj wszystkiego, jest zbyt duży.Nowa usługa została zaktualizowana do korzystania z HttpClientModule i 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')) ); }
Stara usługa, która używa przestarzałego 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); } }
Używam
.do()
( teraz.tap()
) do debugowania.Kiedy pojawia się błąd serwera The
body
tegoResponse
obiektu, które otrzymuję z serwera używam (Lite-serwer) zawiera tylko tekst, stąd powód używamerr.text()
powyżej zamiasterr.json().error
. Może być konieczne dostosowanie tej linii do serwera.Jeśli
res.json()
wywołuje błąd, ponieważ nie może przeanalizować danych JSON,_serverError
nie otrzymaResponse
obiektu, stąd przyczynainstanceof
sprawdzenia.W tym celu plunkerzmień
url
na,./data/data.junk
aby wygenerować błąd.Użytkownicy obu usług powinni mieć kod, który może obsłużyć błąd:
@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 ); } }
źródło
Można to zrobić na kilka sposobów. Obie są bardzo proste. Każdy z przykładów działa świetnie. Możesz skopiować go do swojego projektu i przetestować.
Pierwsza metoda jest lepsza, druga jest nieco przestarzała, ale na razie też działa.
1) Rozwiązanie 1
// File - app.module.ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { ProductService } from './product.service'; import { ProductModule } from './product.module'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [ProductService, ProductModule], bootstrap: [AppComponent] }) export class AppModule { } // File - product.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; // Importing rxjs import 'rxjs/Rx'; import { Observable } from 'rxjs/Rx'; import { catchError, tap } from 'rxjs/operators'; // Important! Be sure to connect operators // There may be your any object. For example, we will have a product object import { ProductModule } from './product.module'; @Injectable() export class ProductService{ // Initialize the properties. constructor(private http: HttpClient, private product: ProductModule){} // If there are no errors, then the object will be returned with the product data. // And if there are errors, we will get into catchError and catch them. getProducts(): Observable<ProductModule[]>{ const url = 'YOUR URL HERE'; return this.http.get<ProductModule[]>(url).pipe( tap((data: any) => { console.log(data); }), catchError((err) => { throw 'Error in source. Details: ' + err; // Use console.log(err) for detail }) ); } }
2) Rozwiązanie 2. To stary sposób, ale nadal działa.
// File - app.module.ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { ProductService } from './product.service'; import { ProductModule } from './product.module'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpModule ], providers: [ProductService, ProductModule], bootstrap: [AppComponent] }) export class AppModule { } // File - product.service.ts import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; // Importing rxjs import 'rxjs/Rx'; import { Observable } from 'rxjs/Rx'; @Injectable() export class ProductService{ // Initialize the properties. constructor(private http: Http){} // If there are no errors, then the object will be returned with the product data. // And if there are errors, we will to into catch section and catch error. getProducts(){ const url = ''; return this.http.get(url).map( (response: Response) => { const data = response.json(); console.log(data); return data; } ).catch( (error: Response) => { console.log(error); return Observable.throw(error); } ); } }
źródło
Funkcje RxJS muszą zostać specjalnie zaimportowane. Prostym sposobem na to jest zaimportowanie wszystkich jego funkcji za pomocą
import * as Rx from "rxjs/Rx"
Następnie upewnij się, że masz dostęp do
Observable
klasy jakoRx.Observable
.źródło
w najnowszej wersji wykorzystania angular4
import { Observable } from 'rxjs/Rx'
zaimportuje wszystkie wymagane rzeczy.
źródło