Angular 常用拦截器

Http拦截器就是拦截发出的请求,对其进行统一添加额外处理,然后放行;对响应进行拦截并作出业务上的判断,决定是否给与返回。

常见拦截器

  • AuthInterceptor 自定义请求头,如 token 之类
// AuthInterceptor.ts
import { Injectable } from "@angular/core";
import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor } from "@angular/common/http";

import { Observable } from "rxjs";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest,
    next: HttpHandler
  ): Observable> {
    const clonedRequest = req.clone({
      headers: req.headers.set("X-CustomAuthHeader", "iloveangular")
    });
    console.log("new headers", clonedRequest.headers.keys());
    return next.handle(clonedRequest);
  }
}

// AppModule.ts
import { AuthInterceptor } from "./interceptors/auth.interceptor";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
  • LogInterceptor 请求日志拦截器,主要记录请求花费时间、状态等
// LogInterceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http';
import { finalize, tap } from 'rxjs/operators';

@Injectable()
export class LogInterceptor implements HttpInterceptor {

  constructor(private loggerService: LoggerService) {}

  intercept(req: HttpRequest, next: HttpHandler) {
    const startTime = Date.now();
    let status: string;

    return next.handle(req).pipe(
        tap(
          event => {
            status = '';
            if (event instanceof HttpResponse) {
              status = 'succeeded';
            }
          },
          error => status = 'failed'
        ),
        finalize(() => {
          const elapsedTime = Date.now() - startTime;
          const message = req.method + " " + req.urlWithParams +" "+ status 
          + " in " + elapsedTime + "ms";
          
          console.log(message);
        })
    );
  }
}
// AppModule.ts
@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: LogInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
  • CacheInterceptor 请求缓存控制器
// Cache.ts
import { HttpRequest, HttpResponse } from '@angular/common/http';

export interface Cache {
  get(req: HttpRequest): HttpResponse | null;
  put(req: HttpRequest, res: HttpResponse): void;
}

export const MAX_CACHE_AGE = 30000; // 单位为毫秒

export interface CacheEntry {
  url: string;
  response: HttpResponse;
  entryTime: number;
}

// CacheService.ts
import { Injectable } from "@angular/core";
import { HttpRequest, HttpResponse } from "@angular/common/http";

import { Cache } from "./cache";
import { CacheEntry, MAX_CACHE_AGE } from "./cache.entry";

@Injectable({
  providedIn: "root"
})
export class CacheService implements Cache {
  cacheMap = new Map();

  constructor() {}

  get(req: HttpRequest): HttpResponse | null {
    // 判断当前请求是否已被缓存,若未缓存则返回null
    const entry = this.cacheMap.get(req.urlWithParams);
    if (!entry) return null;
    // 若缓存命中,则判断缓存是否过期,若已过期则返回null。否则返回请求对应的响应对象  
    const isExpired = Date.now() - entry.entryTime > MAX_CACHE_AGE;
    console.log(`req.urlWithParams is Expired: ${isExpired} `);
    return isExpired ? null : entry.response;
  }

  put(req: HttpRequest, res: HttpResponse): void {
    // 创建CacheEntry对象  
    const entry: CacheEntry = {
      url: req.urlWithParams,
      response: res,
      entryTime: Date.now()
    };
    console.log(`Save entry.url response into cache`);
    // 以请求url作为键,CacheEntry对象为值,保存到cacheMap中。并执行
    // 清理操作,即清理已过期的缓存。
    this.cacheMap.set(req.urlWithParams, entry);
    this.deleteExpiredCache();
  }

  private deleteExpiredCache() {
    this.cacheMap.forEach(entry => {
      if (Date.now() - entry.entryTime > MAX_CACHE_AGE) {
        this.cacheMap.delete(entry.url);
      }
    });
  }
}

// CacheInterceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler } from '@angular/common/http';
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';

import { CacheService } from '../cache.service';

const CACHABLE_URL = "http://jsonplaceholder.typicode.com";

@Injectable()
export class CacheInterceptor implements HttpInterceptor {
    constructor(private cache: CacheService) {}

    intercept(req: HttpRequest, next: HttpHandler) {
        // 判断当前请求是否可缓存
        if (!this.isRequestCachable(req)) { 
           return next.handle(req); 
        }
        // 获取请求对应的缓存对象,若存在则直接返回该请求对象对应的缓存对象
        const cachedResponse = this.cache.get(req);
        if (cachedResponse !== null) {
           return of(cachedResponse);
        }
        // 发送请求至API站点,请求成功后保存至缓存中
        return next.handle(req).pipe(
           tap(event => {
              if (event instanceof HttpResponse) {
                this.cache.put(req, event); 
              }
           })
        );
    }
    
    // 判断当前请求是否可缓存
    private isRequestCachable(req: HttpRequest) {
        return (req.method === 'GET') && (req.url.indexOf(CACHABLE_URL) > -1);
    }
}

// AppModule.ts 
@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: LogInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
  • ResponseInterceptor 接口错误统一处理
import { Injectable } from '@angular/core'
import {
  HttpEvent,
  HttpRequest,
  HttpResponse,
  HttpErrorResponse,
  HttpHandler,
  HttpInterceptor
} from '@angular/common/http'
import { Observable } from 'rxjs'
import { Router } from '@angular/router'
import { tap } from 'rxjs/operators'
import { MessageService } from '../providers'

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {
  constructor(private messageService: MessageService, private router: Router) {}
  intercept(
    req: HttpRequest,
    next: HttpHandler
  ): Observable> {
    return next.handle(req).pipe(
      tap(
        response => {
          if (response instanceof HttpResponse) {
            if (
              response.status === 200 &&
              response.body &&
              parseInt(response.body.code, 10) !== 0
            ) {
              const message = response.body.message || '未知错误'
              if (response.body.code === 109) {
                // token 失效
                this.router.navigate(['/login'])
              }
              this.messageService.addErrorMessage(message)
            }
          }
        },
        error => {
          if (error instanceof HttpErrorResponse) {
            if (error.status >= 500) {
              this.messageService.addErrorMessage(
                `服务器内部错误 ${error.status}`
              )
            } else if (error.status >= 400 && error.status < 500) {
              this.messageService.addErrorMessage(
                `客户端参数错误 ${error.status}`
              )
            }
          }
        }
      )
    )
  }
}

你可能感兴趣的:(前端面试,前端)