共计 1488 个字符,预计需要花费 4 分钟才能阅读完成。
糟糕的网络请求实现会带来什么问题
想象一下电商秒杀场景:当某个热门商品开售时,由于前端没有做好请求队列管理,瞬间爆发的上万次请求直接击垮服务器。又或者在一个实时聊天应用中,因为缺乏重试机制和错误处理,网络波动导致消息频繁发送失败。这些都是网络请求层设计不当引发的典型问题。

技术选型:Axios vs Fetch
拦截器机制差异
- Axios:提供了完善的请求和响应拦截器,可以在请求发出前和响应返回后统一处理数据
- Fetch:原生不支持拦截器,需要自行封装或使用第三方库实现类似功能
取消请求实现方式
- Axios:内置 CancelToken API(新版本也支持 AbortController)
- Fetch:必须配合 AbortController 使用
TypeScript 支持度
- Axios:有完整类型定义,开箱即用
- Fetch:需要额外定义响应类型,接口灵活性更高但开发成本稍大
核心实现
请求封装类 (TypeScript)
/**
* 网络请求封装类
* @param baseURL 基础 API 地址
* @param timeout 超时时间 (ms)
*/
class HttpRequest {constructor(private baseURL: string, private timeout = 5000) {}
// 统一请求方法
async request<T>(config: RequestConfig): Promise<T> {// 实现细节...}
}
错误重试策略(指数退避)
async function requestWithRetry(requestFn: () => Promise<any>,
maxRetries = 3,
baseDelay = 1000
) {
let attempt = 0
while (attempt < maxRetries) {
try {return await requestFn()
} catch (error) {
attempt++
if (attempt >= maxRetries) throw error
// 指数退避延迟
const delay = baseDelay * Math.pow(2, attempt)
await new Promise(resolve => setTimeout(resolve, delay))
}
}
}
请求缓存实现
const cache = new Map<string, {data: any; expire: number}>()
function getCache(key: string) {const item = cache.get(key)
if (!item || Date.now() > item.expire) {cache.delete(key)
return null
}
return item.data
}
性能优化
连接池配置
- HTTP/1.1 下浏览器对同一域名有 6 - 8 个连接限制
- 合理设置 keep-alive 可以复用 TCP 连接
压缩策略
- 服务端开启 gzip/brotli 压缩
- 请求头设置
Accept-Encoding
并发控制(令牌桶算法)
class RateLimiter {constructor(private maxTokens, private refillRate) {// 初始化...}
async acquire() {// 获取令牌逻辑}
}
生产环境避坑指南
Cookie 安全设置
- 关键 Cookie 设置 HttpOnly 和 Secure
- 合理设置 SameSite 属性
CSRF 防护实践
- 使用 CSRF Token
- 验证 Referer 头
内存泄漏排查
- 检查未取消的请求
- 监控 EventListener 数量
思考题
- 如何设计离线优先的请求队列?
- 在微服务架构下如何统一请求监控?
- 针对 API 频繁变更的场景,如何设计更灵活的请求层?
正文完
发表至: 前端开发
近一天内
