面试题答案
一键面试设置与管理请求头以优化性能、加固安全和高效维护
- 性能优化
- 缓存控制:通过设置
Cache - Control
请求头来控制缓存策略。例如,对于不经常变化的数据请求,可以设置Cache - Control: public, max - age = 3600
,表示允许公共缓存,缓存有效期为1小时。在Angular中使用HttpClient
时:
import { HttpClient, HttpHeaders } from '@angular/common/http'; const headers = new HttpHeaders().set('Cache - Control', 'public, max - age = 3600'); this.http.get('/api/data', { headers }).subscribe(response => { // 处理响应 });
- 压缩:启用压缩以减少数据传输量。设置
Accept - Encoding
头为gzip, deflate
,让服务器知道客户端支持的压缩方式。
const headers = new HttpHeaders().set('Accept - Encoding', 'gzip, deflate'); this.http.get('/api/data', { headers }).subscribe(response => { // 处理响应 });
- 缓存控制:通过设置
- 安全加固
- 认证:使用
Authorization
头进行身份验证。例如,对于Bearer令牌认证,设置Authorization: Bearer <token>
。假设从本地存储获取令牌:
const token = localStorage.getItem('token'); const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`); this.http.get('/api/protected - data', { headers }).subscribe(response => { // 处理响应 });
- 防止跨站请求伪造(CSRF):如果后端使用CSRF保护,前端需要在请求头中包含CSRF令牌。假设从cookie中获取CSRF令牌:
import { HttpHeaders } from '@angular/common/http'; const csrfToken = getCsrfTokenFromCookie(); // 自定义函数获取CSRF令牌 const headers = new HttpHeaders().set('X - CSRF - Token', csrfToken); this.http.post('/api/some - action', { data }, { headers }).subscribe(response => { // 处理响应 });
- 认证:使用
- 高效维护
- 使用拦截器:创建一个
HttpInterceptor
来统一处理请求头设置。例如,创建一个AuthInterceptor
来处理认证相关的请求头:
然后在import { Injectable } from '@angular/core'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class AuthInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token = localStorage.getItem('token'); if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request); } }
app.module.ts
中注册拦截器:import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform - browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthInterceptor } from './auth - interceptor'; @NgModule({ imports: [BrowserModule, HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ], bootstrap: [] }) export class AppModule {}
- 使用拦截器:创建一个
可能遇到的问题及解决方案
- 跨域问题
- 问题:由于前端与多个后端微服务交互,可能会遇到跨域问题,浏览器会阻止请求。
- 解决方案:
- 后端配置:在后端微服务中配置CORS(跨域资源共享)。例如,在Node.js中使用
cors
库:const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors());
- 代理服务器:在前端开发环境中,可以使用代理服务器。在Angular项目中,可以通过在
angular.json
中配置代理:
在{ "architect": { "serve": { "proxyConfig": "./proxy.conf.json" } } }
proxy.conf.json
中配置:{ "/api": { "target": "http://backend - microservice - url", "secure": false, "changeOrigin": true } }
- 后端配置:在后端微服务中配置CORS(跨域资源共享)。例如,在Node.js中使用
- 请求频率限制问题
- 问题:后端可能对请求频率进行限制,频繁请求可能导致请求被拒绝。
- 解决方案:
- 客户端缓存:如上述性能优化中的缓存控制,减少不必要的请求。
- 节流与防抖:使用RxJS的
throttleTime
或debounceTime
操作符。例如,对于搜索框的自动完成功能,防止用户快速输入导致过多请求:import { Component } from '@angular/core'; import { fromEvent, Observable } from 'rxjs'; import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; @Component({ selector: 'app - search', templateUrl: './search.component.html' }) export class SearchComponent { constructor(private http: HttpClient) { const searchInput = document.getElementById('search - input') as HTMLInputElement; const search$: Observable<string> = fromEvent(searchInput, 'input').pipe( map((event: any) => event.target.value), debounceTime(300), distinctUntilChanged() ); search$.subscribe(query => { // 发送请求 const headers = new HttpHeaders(); this.http.get(`/api/search?q = ${query}`, { headers }).subscribe(response => { // 处理响应 }); }); } }
- 认证相关问题
- 问题:令牌过期或认证失败导致请求被拒绝。
- 解决方案:
- 令牌刷新:当收到认证失败(如401状态码)的响应时,自动刷新令牌并重试请求。可以在拦截器中处理:
import { Injectable } from '@angular/core'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Observable, catchError, switchMap } from 'rxjs'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: AuthService) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(request).pipe( catchError(error => { if (error.status === 401) { return this.authService.refreshToken().pipe( switchMap(() => { const newToken = this.authService.getToken(); request = request.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } }); return next.handle(request); }) ); } throw error; }) ); } }
- 重新登录:如果令牌刷新失败,引导用户重新登录。可以在上述拦截器的
catchError
中添加逻辑,如导航到登录页面:import { Injectable } from '@angular/core'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Observable, catchError, switchMap } from 'rxjs'; import { Router } from '@angular/router'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: AuthService, private router: Router) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(request).pipe( catchError(error => { if (error.status === 401) { return this.authService.refreshToken().pipe( switchMap(() => { const newToken = this.authService.getToken(); request = request.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } }); return next.handle(request); }), catchError(() => { this.router.navigate(['/login']); throw error; }) ); } throw error; }) ); } }
- 令牌刷新:当收到认证失败(如401状态码)的响应时,自动刷新令牌并重试请求。可以在拦截器中处理: