面试题答案
一键面试跨域解决方案
- CORS(跨域资源共享)
- 服务器端配置:在后端服务器(针对每个不同域名的后端服务)配置允许的源。例如在Node.js中使用
express
框架,可以这样设置:
- 服务器端配置:在后端服务器(针对每个不同域名的后端服务)配置允许的源。例如在Node.js中使用
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.setHeader('Access - Control - Allow - Origin', '*');// 允许所有源访问,生产环境应设置具体域名
res.setHeader('Access - Control - Allow - Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access - Control - Allow - Headers', 'Content - Type, Authorization');
next();
});
- **前端配置**:在Angular项目中,无需额外复杂配置,Angular的`HttpClient`会自动处理CORS相关请求头。只要后端正确配置,即可正常发起跨域请求。
2. 代理服务器
- 搭建代理服务器:可以使用http - proxy - middleware
在开发环境搭建代理。在Angular项目根目录下创建proxy.conf.json
文件:
{
"/api": {
"target": "http://your - backend - domain.com",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
- **在Angular CLI中配置**:修改`angular.json`文件,在`architect.serve`下添加:
"proxyConfig": "./proxy.conf.json"
这样在开发环境,所有以/api
开头的请求都会被代理到指定的后端域名。
不同请求类型和后端服务间的配置和管理
- 封装HTTP服务:在Angular中创建一个通用的HTTP服务,例如
HttpService
,对不同请求类型进行封装。
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(private http: HttpClient) {}
get<T>(url: string, headers?: HttpHeaders): Observable<T> {
return this.http.get<T>(url, { headers });
}
post<T>(url: string, body: any, headers?: HttpHeaders): Observable<T> {
return this.http.post<T>(url, body, { headers });
}
put<T>(url: string, body: any, headers?: HttpHeaders): Observable<T> {
return this.http.put<T>(url, body, { headers });
}
delete<T>(url: string, headers?: HttpHeaders): Observable<T> {
return this.http.delete<T>(url, { headers });
}
}
- 针对不同后端服务管理:根据后端服务的不同域名或功能模块,在服务调用时传入不同的基础URL。例如:
const userServiceBaseUrl = 'http://user - backend - domain.com/api';
const productServiceBaseUrl = 'http://product - backend - domain.com/api';
// 使用封装的HttpService
this.httpService.get(`${userServiceBaseUrl}/users`);
this.httpService.post(`${productServiceBaseUrl}/products`, { name: 'new product' });
性能优化
- 缓存策略
- 使用RxJS的
shareReplay
操作符:对于一些不经常变化的数据请求,例如获取配置信息,可以使用shareReplay
进行缓存。
- 使用RxJS的
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ConfigService {
private config$: Observable<any>;
constructor(private http: HttpClient) {}
getConfig(): Observable<any> {
if (!this.config$) {
this.config$ = this.http.get('/api/config').pipe(
shareReplay(1)
);
}
return this.config$;
}
}
- **设置合理的缓存时间**:对于缓存的数据,可以设置过期时间。例如,在获取数据时记录时间戳,每次获取缓存数据时检查是否过期。
private cache: { [url: string]: { data: any; timestamp: number } } = {};
private cacheDuration = 60 * 1000; // 1分钟
get<T>(url: string): Observable<T> {
if (this.cache[url] && Date.now() - this.cache[url].timestamp < this.cacheDuration) {
return of(this.cache[url].data);
}
return this.http.get<T>(url).pipe(
tap(data => {
this.cache[url] = { data, timestamp: Date.now() };
})
);
}
- 请求合并
- 使用RxJS的
forkJoin
:当多个请求相互独立但需要同时处理结果时,可以使用forkJoin
合并请求。例如,同时获取用户信息和用户订单信息:
- 使用RxJS的
import { Component } from '@angular/core';
import { HttpService } from './http.service';
import { forkJoin } from 'rxjs';
@Component({
selector: 'app - example',
templateUrl: './example.component.html'
})
export class ExampleComponent {
constructor(private httpService: HttpService) {}
ngOnInit() {
const user$ = this.httpService.get('/api/user');
const orders$ = this.httpService.get('/api/orders');
forkJoin([user$, orders$]).subscribe(([user, orders]) => {
// 处理用户和订单数据
});
}
}
- **去重合并**:对于短时间内重复的请求,可以进行去重。例如,维护一个正在进行中的请求队列,当有相同请求时,返回已有的请求Observable,而不是发起新请求。
private inProgressRequests: { [url: string]: Observable<any> } = {};
get<T>(url: string): Observable<T> {
if (this.inProgressRequests[url]) {
return this.inProgressRequests[url];
}
const request$ = this.http.get<T>(url);
this.inProgressRequests[url] = request$;
request$.subscribe(() => {
delete this.inProgressRequests[url];
});
return request$;
}