Làm cách nào để bắt ngoại lệ chính xác từ http.request ()?


132

Một phần mã của tôi:

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() tạo ngoại lệ trong bảng điều khiển của trình duyệt:

NGOẠI TRỪ GỐC: TypeError: this.http.request (...). Map (...). Catch không phải là một chức năng

Câu trả lời:


213

Có lẽ bạn có thể thử thêm điều này trong nhập khẩu của bạn:

import 'rxjs/add/operator/catch';

Bạn cũng có thể làm:

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

Mỗi bình luận:

NGOẠI TRỪ: TypeError: Observable_1.Observable.throw không phải là một chức năng

Tương tự, đối với điều đó, bạn có thể sử dụng:

import 'rxjs/add/observable/throw';

2
Cảm ơn bạn đã giúp đỡ, nó hoạt động. Sau đó tôi có vấn đề tương tự với throw()chức năng. Tôi đã thêm dòng này import 'rxjs/Rx';thay thế. Bây giờ tất cả các nhà khai thác hoạt động đúng.
mnv

Bạn đã mô phỏng một lỗi để xem nếu .catchthực sự làm việc? Điều đó .subscribe() làm việc chắc chắn.
acdcjunior

1
Vâng, vấn đề thứ hai là EXCEPTION: TypeError: Observable_1.Observable.throw is not a function. Nó có thể được sửa với câu trả lời @MattScarpino hoặc trong maner từ plunker này như tôi đã nói ở trên: angular.io/resource/live-examples/server-c truyền thông / t /
mnv

16
Chỉ cần nhập quá nhiều: import 'rxjs/add/observable/throw';và không nhập mọi thứ, nó quá lớn.
dfsq

Giải pháp tuyệt vời ,, rất hữu ích, tôi có thể thêm (err) là loại Phản hồi
Mohammed Suez

76

Dịch vụ mới được cập nhật để sử dụng HttpClientModule và 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'))
            );
    }

Dịch vụ cũ, sử dụng httpModule không dùng nữa:

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

Tôi sử dụng .do()( bây giờ.tap() ) để gỡ lỗi.

Khi có một lỗi máy chủ, các bodycủa Responseđối tượng tôi nhận được từ các máy chủ Tôi đang sử dụng (Lite-server) chỉ chứa văn bản, do đó là lý do tôi sử dụng err.text()trên hơn err.json().error. Bạn có thể cần phải điều chỉnh dòng đó cho máy chủ của bạn.

Nếu res.json()phát sinh lỗi vì nó không thể phân tích dữ liệu JSON, _serverErrorsẽ không nhận được Responseđối tượng, do đó là lý do để instanceofkiểm tra.

Trong này plunker, thay đổi urlđể ./data/data.junktạo ra một lỗi.


Người dùng của một trong hai dịch vụ nên có mã có thể xử lý lỗi:

@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

Có nhiều hướng khác nhau để làm điều đó. Cả hai đều rất đơn giản. Mỗi ví dụ hoạt động tuyệt vời. Bạn có thể sao chép nó vào dự án của bạn và kiểm tra nó.

Phương pháp đầu tiên là tốt hơn, phương pháp thứ hai là một chút lỗi thời, nhưng cho đến nay nó cũng hoạt động.

1) Giải pháp 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) Giải pháp 2. Đó là cách cũ nhưng vẫn hoạt động.

// 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

Các chức năng RxJS cần phải được nhập cụ thể. Một cách dễ dàng để làm điều này là nhập tất cả các tính năng của nó vớiimport * as Rx from "rxjs/Rx"

Sau đó hãy chắc chắn để truy cập các Observablelớp như Rx.Observable.


15
Rxjs là một tệp rất lớn, nếu bạn nhập tất cả các tính năng của nó, nó sẽ tăng thời gian tải của bạn
Soumya Gangamwar

Bạn không nên chỉ nhập mọi thứ từ Rxjs nếu bạn chỉ cần một hoặc hai toán tử.
marcel-k

-4

trong phiên bản mới nhất của angular4 sử dụng

import { Observable } from 'rxjs/Rx'

nó sẽ nhập tất cả những thứ cần thiết


20
Đừng làm điều này, nó sẽ nhập tất cả Rxjs.
marcel-k

Và do đó sẽ dẫn đến tăng kích thước bó!
Tushar Walzade
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.