برای شروع بهتر است مفهوم Interceptor را درک کنیم.
Interceptor
Interceptor بخشی از کد است که یک دستورالعمل را از زمان راه اندازی تا قبل از تمام شدن رهگیری میکند. در محیط انگولار، زمانی که HTTP سورسی خارج از محیط کلاینت را فراخوانی میکند، معمولا از Interceptor استفاده میشود.
Error Interceptor
Error Interceptor نوع خاصی از Interceptor است و برای هندل کردن خطاهایی که هنگام درخواست HTTP بوجود می آیند استفاده میشود. خطا ممکن است در محیط کاربر (مرورگر) باشد یا از سمت سرور رخ دهد. هندل کردن خطاها برای اپلیکیشن های مدرن خیلی مهم است، زیرا بعد از fail شدن پاسخ باید کارهای خاصی انجام دهیم (مثلا به کاربر toast نشان دهیم یا دکمه تلاش مجدد نمایش دهیم). درست در این نقطه است که میتوانیم از مکانیسم Error Interceptor استفاده کنیم.
برای اینکه مفهوم Error Interceptor بهتر درک شود مثال ساده ای نوشته ام. در این مثال سرویس متد ساده ای وجود دارد که در آن درخواست HTTP صورت میگیرد. درخواست HTTP بخاطر مسیر اشتباه fail میشود و ما ارور را میگیریم.
برای شروع دکمه ای تعریف میکنیم که درخواست API میدهد.
app.component.html
<div> <button (click)="someApiCall()">Click me!</button> </div>
در مرحله بعد بایدکدهایی بنویسیم که به کلیک دکمه پاسخ دهد. قبل از هرکاری لازم است سرویسی با متد getData() با درخواست HTTP بنویسیم.
data.service.ts
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class DataService { constructor(private http: HttpClient) { } getData(): Observable<any> { const url = 'Some wrong url for test purpose'; return this.http.get(url); } }
کلیک دکمه getData() را فراخوانی میکند که دارای API با نقطه پایان اشتباه است. نقطه پایان API تعمدا اشتباه است تا با خطا مواجه شویم و عملکرد هندل کردن خطا ها در Error Interceptor را ببینیم.
برای دیدن عملکرد Error Interceptor فایلی تازه در فولدر سرویس ها با نام httperrorinterceptor.service.ts ایجاد میکنیم. در این فایل قرار است منطق Error Interceptor نوشته شود. در این فایل ساختار اصلی هندل کردن خطاها وجود دارد و خواهید دید که چگونه انواع خطاها را هندل کنید. ابتدا محتواها زیر را در فایل httperrorinterceptor.service.ts مینویسیم.
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; export class HttpErrorInterceptor implements HttpInterceptor { intercept(request: HttpRequest, next: HttpHandler): Observable<httpevent<any>> { return next.handle(request) .pipe( catchError((error: HttpErrorResponse) => { let errorMsg = ''; if (error.error instanceof ErrorEvent) { console.log('this is client side error'); errorMsg = `Error: ${error.error.message}`; } else { console.log('this is server side error'); errorMsg = `Error Code: ${error.status}, Message: ${error.message}`; } console.log(errorMsg); return throwError(errorMsg); }) ) } }
اتفاقات زیادی در فایل بالا رخ میدهد که مهمترین آن به شرح زیر است.
- کلاس HttpErrorInterceptor اینترفیس HttpInterceptor را پیاده سازی کرده است که خود بخشی از npm پکیج @angular/common/http است. بنابراین متد intercept() پیاده سازی شده است.
- متد interceptor() دو پارامتر با نام های request که HttpRequest و next که HttpHandler است میگیرد.
- متد interceptor() یک Observable از نوع HttpEvent برمیگرداند که signature آن از نوع any است. شما میتوانید هر نوعی به آن اختصاص دهید.
- با اپراتور rxjs pipe() بررسی میکنیم آیا خطا instanceی از ErrorEvent است یا نه. اینکار معلوم میکند خطا از سمت کاربر بوجود آمده یا نه.
- درغیر این صورت خطا را از سمت کاربر است.
- برای راحتی نمایش ما خطا را با کمک عملگرهای ES6 فورمت دادیم و خطا را از طریق throwError() که یکی از اپراتورهای rxjs است نمایش میدهیم.
در مرحله آخر، ما باید فایل بالا را در app module ثبت کنیم. بنابراین، در این فایل تغییرات زیر را اعمال کنید.
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpErrorInterceptor } from './services/httpinterceptor.service'; @NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }
به همین راحتی کلاس HttpErrorInterceptor را از فایل سرویس آوردیم و در آرایه providers ثبت کردیم. نکته ای که باید به آن دقت کنید این است که فایل interceptor بعنوان HTTP_INTERCEPTORS ارائه شده است (provided). همچنین ما گزینه multi را true کردیم تا ارائه چندین interceptor ممکن شود.
به نقل از: medium