programing

Angular HttpClient에서 오류를 감지하는 중

telebox 2023. 4. 27. 22:10
반응형

Angular HttpClient에서 오류를 감지하는 중

다음과 같은 데이터 서비스가 있습니다.

@Injectable()
export class DataService {
    baseUrl = 'http://localhost'
        constructor(
        private httpClient: HttpClient) {
    }
    get(url, params): Promise<Object> {

        return this.sendRequest(this.baseUrl + url, 'get', null, params)
            .map((res) => {
                return res as Object
            })
            .toPromise();
    }
    post(url, body): Promise<Object> {
        return this.sendRequest(this.baseUrl + url, 'post', body)
            .map((res) => {
                return res as Object
            })
            .toPromise();
    }
    patch(url, body): Promise<Object> {
        return this.sendRequest(this.baseUrl + url, 'patch', body)
            .map((res) => {
                return res as Object
            })
            .toPromise();
    }
    sendRequest(url, type, body, params = null): Observable<any> {
        return this.httpClient[type](url, { params: params }, body)
    }
}

HTTP 오류(예: 404)가 발생하면 "ERROR Error: 잡히지 않음(약속): core.es5.js에서 [오브젝트] 이 경우 어떻게 처리합니까?

필요에 따라 몇 가지 옵션이 있습니다.하고자 할 에는 "" " " " " " 를 합니다.catch당신의 요청에글로벌 솔루션을 추가하려면 다음을 사용합니다.HttpInterceptor.

아래 솔루션에 대한 작업 데모플런커여십시오.

tl;dr

▁a를 하면 됩니다..catch() 는또..subscribe() 예:

import 'rxjs/add/operator/catch'; // don't forget this, or you'll get a runtime error
this.httpClient
      .get("data-url")
      .catch((err: HttpErrorResponse) => {
        // simple logging, but you can do a lot more, see below
        console.error('An error occurred:', err.error);
      });

// or
this.httpClient
      .get("data-url")
      .subscribe(
        data => console.log('success', data),
        error => console.log('oops', error)
      );

그러나 이에 대한 자세한 내용은 아래를 참조하십시오.


방법(로컬) 솔루션: 로그 오류 및 폴백 응답 반환

한 곳에서만 오류를 처리해야 하는 경우 다음을 사용할 수 있습니다.catch완전히 실패하는 대신 기본값(또는 빈 응답)을 반환합니다.당신은 또한 필요하지 않습니다..map캐스팅을 위해 일반적인 기능을 사용할 수 있습니다.출처:Angular.io - 오류 세부 정보를 가져옵니다.

인 그서릭, 네제래..get()방법은 다음과 같습니다.

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from "@angular/common/http";
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/retry'; // don't forget the imports

@Injectable()
export class DataService {
    baseUrl = 'http://localhost';
    constructor(private httpClient: HttpClient) { }

    // notice the <T>, making the method generic
    get<T>(url, params): Observable<T> {
      return this.httpClient
          .get<T>(this.baseUrl + url, {params})
          .retry(3) // optionally add the retry
          .catch((err: HttpErrorResponse) => {

            if (err.error instanceof Error) {
              // A client-side or network error occurred. Handle it accordingly.
              console.error('An error occurred:', err.error.message);
            } else {
              // The backend returned an unsuccessful response code.
              // The response body may contain clues as to what went wrong,
              console.error(`Backend returned code ${err.status}, body was: ${err.error}`);
            }

            // ...optionally return a default fallback value so app can continue (pick one)
            // which could be a default value
            // return Observable.of<any>({my: "default value..."});
            // or simply an empty observable
            return Observable.empty<T>();
          });
     }
}

오류를 처리하면 URL의 서비스 상태가 좋지 않은 경우에도 앱을 계속 진행할 수 있습니다.

이 요청별 솔루션은 대부분 각 방법에 특정 기본 응답을 반환하려는 경우에 유용합니다.그러나 오류 표시(또는 글로벌 기본 응답)에만 관심이 있는 경우 아래 설명된 것처럼 인터셉터를 사용하는 것이 더 나은 해결 방법입니다.

여기서 작업 데모플런커를 실행합니다.


고급 사용:모든 요청 또는 응답 가로채기

다시 한 번 Angular.io 가이드에는 다음과 같은 내용이 표시됩니다.

의 주요 @angular/common/http가로채기는 응용 프로그램과 백엔드 사이에 있는 가로채기를 선언하는 기능입니다.응용프로그램이 요청을 할 때, 인터셉터는 서버로 보내기 전에 요청을 변환하고, 인터셉터는 응용프로그램이 보기 전에 응답을 반환하는 도중에 변환할 수 있습니다.이 기능은 인증에서 로깅에 이르기까지 모든 작업에 유용합니다.

물론 오류를 매우 간단한 방법으로 처리하는 데 사용할 수 있습니다(디모플런커).

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse,
         HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/retry'; // don't forget the imports

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request)
      .catch((err: HttpErrorResponse) => {

        if (err.error instanceof Error) {
          // A client-side or network error occurred. Handle it accordingly.
          console.error('An error occurred:', err.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          console.error(`Backend returned code ${err.status}, body was: ${err.error}`);
        }

        // ...optionally return a default fallback value so app can continue (pick one)
        // which could be a default value (which has to be a HttpResponse here)
        // return Observable.of(new HttpResponse({body: [{name: "Default value..."}]}));
        // or simply an empty observable
        return Observable.empty<HttpEvent<any>>();
      });
  }
}

인터셉터 제공:간단히 선언합니다.HttpErrorInterceptor위는 당신의 앱이 그것을 사용하도록 만들지 않습니다.다음과 같이 인터셉트로 제공하여 앱 모듈에 연결해야 합니다.

import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './path/http-error.interceptor';

@NgModule({
  ...
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptor,
    multi: true,
  }],
  ...
})
export class AppModule {}

참고: 오류 인터셉터와 일부 로컬 오류 처리가 모두 있는 경우, 오류가 로컬 오류 처리에 도달하기 전에 항상 인터셉터에서 처리되기 때문에 로컬 오류 처리가 트리거되지 않을 가능성이 높습니다.

여기서 작업 데모플런커를 실행합니다.

최신 RxJs 기능(v.6)으로 HttpInterceptor 사용에 대한 acdc주니어의 답변을 업데이트해드리겠습니다.

import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpErrorResponse,
  HttpHandler,
  HttpEvent,
  HttpResponse
} from '@angular/common/http';

import { Observable, EMPTY, throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.error instanceof Error) {
          // A client-side or network error occurred. Handle it accordingly.
          console.error('An error occurred:', error.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          console.error(`Backend returned code ${error.status}, body was: ${error.error}`);
        }

        // If you want to return a new response:
        //return of(new HttpResponse({body: [{name: "Default value..."}]}));

        // If you want to return the error on the upper level:
        //return throwError(error);

        // or just return nothing:
        return EMPTY;
      })
    );
  }
}

께의 .HTTPClient도 였습니다.Http되었습니다.HttpInterceptorAPI.API.

AFAIK의 목표 중 하나는 모든 HTTP 송신 요청 및 수신 응답에 기본 동작을 추가하는 것입니다.

따라서 기본 오류 처리 동작을 추가하고 싶다고 가정하고,.catch()가능한 모든 http.get/post/etc 메서드는 관리하기가 터무니없이 어렵습니다.

이 작업은 예를 들어 다음과 같은 방법으로 수행할 수 있습니다.HttpInterceptor:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { _throw } from 'rxjs/observable/throw';
import 'rxjs/add/operator/catch';

/**
 * Intercepts the HTTP responses, and in case that an error/exception is thrown, handles it
 * and extract the relevant information of it.
 */
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    /**
     * Intercepts an outgoing HTTP request, executes it and handles any error that could be triggered in execution.
     * @see HttpInterceptor
     * @param req the outgoing HTTP request
     * @param next a HTTP request handler
     */
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(req)
            .catch(errorResponse => {
                let errMsg: string;
                if (errorResponse instanceof HttpErrorResponse) {
                    const err = errorResponse.message || JSON.stringify(errorResponse.error);
                    errMsg = `${errorResponse.status} - ${errorResponse.statusText || ''} Details: ${err}`;
                } else {
                    errMsg = errorResponse.message ? errorResponse.message : errorResponse.toString();
                }
                return _throw(errMsg);
            });
    }
}

/**
 * Provider POJO for the interceptor
 */
export const ErrorInterceptorProvider = {
    provide: HTTP_INTERCEPTORS,
    useClass: ErrorInterceptor,
    multi: true,
};

app.s.ts.

import { ErrorInterceptorProvider } from 'somewhere/in/your/src/folder';

@NgModule({
   ...
   providers: [
    ...
    ErrorInterceptorProvider,
    ....
   ],
   ...
})
export class AppModule {}

OP에 대한 추가 정보: 강력한 유형 없이 http.get/post/etc를 호출하는 것은 API를 최적으로 사용하지 않습니다.서비스의 모양은 다음과 같습니다.

// These interfaces could be somewhere else in your src folder, not necessarily in your service file
export interface FooPost {
 // Define the form of the object in JSON format that your 
 // expect from the backend on post
}

export interface FooPatch {
 // Define the form of the object in JSON format that your 
 // expect from the backend on patch
}

export interface FooGet {
 // Define the form of the object in JSON format that your 
 // expect from the backend on get
}

@Injectable()
export class DataService {
    baseUrl = 'http://localhost'
    constructor(
        private http: HttpClient) {
    }

    get(url, params): Observable<FooGet> {

        return this.http.get<FooGet>(this.baseUrl + url, params);
    }

    post(url, body): Observable<FooPost> {
        return this.http.post<FooPost>(this.baseUrl + url, body);
    }

    patch(url, body): Observable<FooPatch> {
        return this.http.patch<FooPatch>(this.baseUrl + url, body);
    }
}

Promises대신 서비스 방법에서Observables또 다른 나쁜 결정입니다.

그리고 한 가지 추가적인 조언이 있습니다. 만약 당신이 TYPE 스크립트를 사용하고 있다면, 그것의 타입 부분을 사용하기 시작하세요.언어의 가장 큰 장점 중 하나를 잃게 됩니다. 즉, 자신이 다루고 있는 가치의 유형을 아는 것입니다.

만약 당신이 제 생각에 각진 서비스의 좋은 예를 원한다면, 다음 요점을 보세요.

Angular 6+의 경우 .catch는 관찰 가능에서 직접 작동하지 않습니다.사용해야 합니다.

.pipe(catchError(this.errorHandler))

아래 코드:

import { IEmployee } from './interfaces/employee';
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {

  private url = '/assets/data/employee.json';

  constructor(private http: HttpClient) { }

  getEmployees(): Observable<IEmployee[]> {
    return this.http.get<IEmployee[]>(this.url)
                    .pipe(catchError(this.errorHandler));  // catch error
  }

  /** Error Handling method */

  errorHandler(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.error(
        `Backend returned code ${error.status}, ` +
        `body was: ${error.error}`);
    }
    // return an observable with a user-facing error message
    return throwError(
      'Something bad happened; please try again later.');
  }
}

자세한 내용은 Http용 Angular Guide를 참조하십시오.

(이전 API에서 수행된 방식과 비교하면) 상당히 간단합니다.

Angular 공식 가이드에서 출처(복사하여 붙여넣기)

 http
  .get<ItemsResponse>('/api/items')
  .subscribe(
    // Successful responses call the first callback.
    data => {...},
    // Errors will call this callback instead:
    err => {
      console.log('Something went wrong!');
    }
  );

Angular 8 HttpClient 오류 처리 서비스 예제

여기에 이미지 설명 입력

api.service.ts

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
    import { Student } from '../model/student';
    import { Observable, throwError } from 'rxjs';
    import { retry, catchError } from 'rxjs/operators';

    @Injectable({
      providedIn: 'root'
    })
    export class ApiService {

      // API path
      base_path = 'http://localhost:3000/students';

      constructor(private http: HttpClient) { }

      // Http Options
      httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      }

      // Handle API errors
      handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
          // A client-side or network error occurred. Handle it accordingly.
          console.error('An error occurred:', error.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          console.error(
            `Backend returned code ${error.status}, ` +
            `body was: ${error.error}`);
        }
        // return an observable with a user-facing error message
        return throwError(
          'Something bad happened; please try again later.');
      };


      // Create a new item
      createItem(item): Observable<Student> {
        return this.http
          .post<Student>(this.base_path, JSON.stringify(item), this.httpOptions)
          .pipe(
            retry(2),
            catchError(this.handleError)
          )
      }

     ........
     ........

    }

import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

const PASSENGER_API = 'api/passengers';

getPassengers(): Observable<Passenger[]> {
  return this.http
    .get<Passenger[]>(PASSENGER_API)
    .pipe(catchError((error: HttpErrorResponse) => throwError(error)));
}

Angular 13에서

      this.callApiSrvice.GetProducts()
    .subscribe({
      next: (data) => 
      {
        this.products = data;
      },
      error: (e) => 
      {
        
        console.log('Error while loading the product data');
      }      
    })

여러분은 아마 다음과 같은 것을 갖고 싶을 것입니다.

this.sendRequest(...)
.map(...)
.catch((err) => {
//handle your error here
})

서비스를 어떻게 이용하느냐에 따라 차이가 크지만 이것이 기본적인 경우입니다.

@acdcjunior answer에 이어 다음과 같이 구현했습니다.

서비스:

  get(url, params): Promise<Object> {

            return this.sendRequest(this.baseUrl + url, 'get', null, params)
                .map((res) => {
                    return res as Object
                }).catch((e) => {
                    return Observable.of(e);
                })
                .toPromise();
        }

호출자:

this.dataService.get(baseUrl, params)
            .then((object) => {
                if(object['name'] === 'HttpErrorResponse') {
                            this.error = true;
                           //or any handle
                } else {
                    this.myObj = object as MyClass 
                }
           });

여기에 제공된 솔루션에서 오류를 발견할 수 없는 경우, 서버가 CORS 요청을 처리하고 있지 않을 수 있습니다.

이 경우 Angular는 물론 Javascript도 오류 정보에 액세스할 수 있습니다.

다음을 포함하는 경고를 콘솔에서 찾습니다.CORB또는Cross-Origin Read Blocking.

또한 오류를 처리하기 위해 구문이 변경되었습니다(다른 모든 답변에 설명됨).이제 다음과 같은 파이프 가능 연산자를 사용합니다.

this.service.requestsMyInfo(payload).pipe(
    catcheError(err => {
        // handle the error here.
    })
);

가로채기를 사용하면 오류를 발견할 수 있습니다.다음은 코드입니다.

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    //Get Auth Token from Service which we want to pass thr service call
    const authToken: any = `Bearer ${sessionStorage.getItem('jwtToken')}`
    // Clone the service request and alter original headers with auth token.
    const authReq = req.clone({
      headers: req.headers.set('Content-Type', 'application/json').set('Authorization', authToken)
    });

    const authReq = req.clone({ setHeaders: { 'Authorization': authToken, 'Content-Type': 'application/json'} });

    // Send cloned request with header to the next handler.
    return next.handle(authReq).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        console.log("Service Response thr Interceptor");
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        console.log("err.status", err);
        if (err.status === 401 || err.status === 403) {
          location.href = '/login';
          console.log("Unauthorized Request - In case of Auth Token Expired");
        }
      }
    });
  }
}

당신은 이 블로그를 선호할 수 있습니다.그것에 대한 간단한 예를 들어보자면

더 나쁜 것은 단순히 사용하여 생성할 수 없는 적절한 스택 추적이 없다는 것입니다.HttpInterceptor(수정되기를 바랍니다).오류를 생성한 라인이나 클래스가 아니라 존과 rxjs 쓸모없는 블롯의 로드만 얻을 수 있습니다.

이렇게 하려면 확장된 스택을 생성해야 합니다.HttpClient따라서 프로덕션 환경에서 이 작업을 수행하는 것은 바람직하지 않습니다.

/**
 * Extended HttpClient that generates a stack trace on error when not in a production build.
 */
@Injectable()
export class TraceHttpClient extends HttpClient {
  constructor(handler: HttpHandler) {
    super(handler);
  }

  request(...args: [any]): Observable<any> {
    const stack = environment.production ? null : Error().stack;
    return super.request(...args).pipe(
      catchError((err) => {
        // tslint:disable-next-line:no-console
        if (stack) console.error('HTTP Client error stack\n', stack);
        return throwError(err);
      })
    );
  }
}

언급URL : https://stackoverflow.com/questions/46019771/catching-errors-in-angular-httpclient

반응형