تايب سكريبت - كيفية التقاط الاستثناء بشكل صحيح من 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 الإصدار 5.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'))
);
}
الخدمة القديمة، التي تستخدم وحدة Http المهملة:
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()) لأغراض التصحيح.
عندما يحدث خطأ في الخادم، فإن body لكائن Response الذي أحصل عليه من الخادم الذي أستخدمه (lite-server) يحتوي على نص فقط، ومن هنا السبب في استخدامي err.text() أعلاه بدلاً من err.json().error. قد تحتاج إلى تعديل هذا السطر ليتناسب مع خادمك.
إذا تسبب 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
);
}
}
