จะจับข้อยกเว้นอย่างถูกต้องจาก http.request () ได้อย่างไร?


133

ส่วนหนึ่งของรหัสของฉัน:

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() สร้างข้อยกเว้นในคอนโซลของเบราว์เซอร์:

ORIGINAL EXCEPTION: TypeError: this.http.request (... ). map (... ). catch ไม่ใช่ฟังก์ชัน

คำตอบ:


214

บางทีคุณอาจลองเพิ่มสิ่งนี้ในการนำเข้าของคุณ:

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
ขอบคุณสำหรับความช่วยเหลือมันได้ผล หลังจากนั้นฉันมีปัญหาเดียวกันกับthrow()ฟังก์ชัน ฉันเพิ่มบรรทัดนี้import 'rxjs/Rx';แทน ขณะนี้ตัวดำเนินการทั้งหมดทำงานได้อย่างถูกต้อง
mnv

คุณได้จำลองข้อผิดพลาดเพื่อดูว่าใช้.catchงานได้จริงหรือไม่? ที่ได้.subscribe() ผลแน่นอน
acdcjunior

1
EXCEPTION: TypeError: Observable_1.Observable.throw is not a functionใช่ปัญหาที่สองคือ อาจได้รับการแก้ไขด้วยคำตอบ @MattScarpino หรือใน maner จาก plunker นี้ตามที่ฉันได้กล่าวไว้ข้างต้น: angular.io/resources/live-examples/server-communication/ts/…
mnv

16
เพียงแค่นำเข้า throw ด้วย: import 'rxjs/add/observable/throw';และอย่านำเข้าทุกอย่างมันใหญ่เกินไป
dfsq

ทางออกที่ดีมีประโยชน์มากฉันอาจเพิ่ม (err) เป็นประเภทตอบกลับ
Mohammed Suez

77

บริการใหม่ที่อัปเดตเพื่อใช้ 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() ) สำหรับการดีบัก

เมื่อมีข้อผิดพลาดเซิร์ฟเวอร์ที่bodyของResponseวัตถุที่ฉันได้รับจากเซิร์ฟเวอร์ฉันใช้ (Lite เซิร์ฟเวอร์) มีข้อความเพียงเพราะฉะนั้นเหตุผลที่ผมใช้ข้างต้นมากกว่า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
            );
    }
}

4

มีหลายวิธีในการดำเนินการนี้ ทั้งสองอย่างง่ายมาก แต่ละตัวอย่างใช้งานได้ดี คุณสามารถคัดลอกลงในโครงการของคุณและทดสอบได้

วิธีแรกเป็นวิธีที่ดีกว่าวิธีที่สองค่อนข้างล้าสมัย แต่ก็ใช้ได้ผลเช่นกัน

1) แนวทางแก้ไข 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) วิธีแก้ไข 2. เป็นวิธีเก่า แต่ยังใช้งานได้

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

-1

จำเป็นต้องนำเข้าฟังก์ชัน RxJS โดยเฉพาะ วิธีง่ายๆในการทำเช่นนี้คือการนำเข้าคุณสมบัติทั้งหมดด้วยไฟล์import * as Rx from "rxjs/Rx"

จากนั้นให้แน่ใจว่าจะเข้าถึงระดับเป็นObservableRx.Observable


15
Rxjs เป็นไฟล์ที่ใหญ่มากหากคุณนำเข้าทั้งหมดของมันจะทำให้คุณเสียเวลาโหลด
Soumya Gangamwar

คุณไม่ควรนำเข้าทุกอย่างจาก Rxjs หากคุณต้องการตัวดำเนินการเพียงหนึ่งหรือสองตัว
marcel-k

-4

ในเวอร์ชันล่าสุดของการใช้ angular4

import { Observable } from 'rxjs/Rx'

มันจะนำเข้าสิ่งที่จำเป็นทั้งหมด


20
อย่าทำเช่นนี้มันจะนำเข้า Rxjs ทั้งหมด
marcel-k

และจะส่งผลให้ขนาดมัดใหญ่ขึ้น!
Tushar Walzade
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.