每次接手新的后台管理系统项目,我都会先花半天时间搭建请求层架构。这看似简单的网络请求模块,往往藏着无数业务逻辑的暗礁。上周团队新来的工程师小王就踩了坑——401状态码处理不当导致页面死循环,文件下载功能在Safari浏览器失效,业务错误提示被重复弹窗淹没。这些问题看似独立,实则都源于请求层设计缺乏全局视角。
在Ant Design Pro技术栈中,umi-request作为底层请求库,其设计优劣直接影响整个应用的健壮性。不同于简单的API调用封装,企业级应用需要建立三层防御体系:
typescript复制// 典型的企业级请求层架构
const enterpriseRequest = {
networkLayer: { /* 处理HTTP规范 */ },
businessLayer: { /* 解析业务协议 */ },
presentationLayer: { /* 控制UI反馈 */ }
}
提示:良好的请求层设计应该像OSI网络模型那样分层解耦,每层只关注自己的职责范围
Token过期处理看似简单,但实际场景中隐藏着多个技术要点。以下是我们在金融项目中总结的最佳实践:
| 场景类型 | 处理方式 | 技术实现要点 |
|---|---|---|
| 页面初始化请求 | 立即跳转登录页 | 在拦截器中判断isInitRequest |
| 表单提交请求 | 保存表单数据后跳转 | sessionStorage临时存储 |
| 背景轮询请求 | 静默处理不触发跳转 | 检查请求头X-Silent-Request |
typescript复制// 增强版401处理逻辑
if (status === 401) {
if (options.headers['X-Silent-Request']) {
return Promise.reject(error)
}
const currentPath = history.location.pathname
if (!whiteList.includes(currentPath)) {
sessionStorage.setItem('FORM_DATA', JSON.stringify(formData))
history.push(`/login?redirect=${encodeURIComponent(currentPath)}`)
}
}
当多个并行请求同时返回401时,需要防止登录页被重复跳转。我们采用原子锁机制解决:
typescript复制let isRedirecting = false
request.interceptors.response.use((response) => {
if (response.status === 401 && !isRedirecting) {
isRedirecting = true
// 执行跳转逻辑
setTimeout(() => { isRedirecting = false }, 1000)
}
return response
})
前端处理文件下载需要考虑的边界情况远超大多数开发者预期。以下是经过20+项目验证的可靠方案:
typescript复制const downloadFile = async (url, filename) => {
const blob = await request.get(url, {
parseResponse: false,
responseType: 'blob'
})
const link = document.createElement('a')
const objectUrl = window.URL.createObjectURL(blob)
link.href = objectUrl
link.download = filename
document.body.appendChild(link)
link.click()
setTimeout(() => {
document.body.removeChild(link)
window.URL.revokeObjectURL(objectUrl)
}, 100)
}
typescript复制// Safari浏览器检测逻辑
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
if (isSafari) {
// 特殊处理Safari的blob下载
window.open(url, '_blank')
} else {
// 标准下载流程
}
后端返回的业务错误码处理需要建立企业级规范,我们推荐采用错误码分类体系:
| 错误级别 | 编码范围 | 处理方式 | 用户提示 |
|---|---|---|---|
| 系统错误 | 10000-19999 | 记录日志并告警 | "系统繁忙,请稍后重试" |
| 业务错误 | 20000-29999 | 展示具体错误信息 | 后端返回的msg字段 |
| 权限错误 | 30000-39999 | 跳转权限申请页面 | "请联系管理员开通权限" |
typescript复制const businessErrorHandler = (response) => {
const { code, msg } = response
if (code >= 10000 && code < 20000) {
// 系统级错误
Sentry.captureException(new Error(msg))
showSystemError()
} else if (code >= 20000 && code < 30000) {
// 业务级错误
showToast(msg)
} else {
// 默认处理
showDefaultError()
}
return Promise.reject(response)
}
完善的请求层还需要考虑性能指标采集和监控告警:
typescript复制request.interceptors.response.use((response) => {
const endTime = Date.now()
const duration = endTime - startTime
// 上报性能数据
perfTracker.track({
url: response.url,
status: response.status,
duration
})
return response
})
typescript复制const tracedRequest = (url, options) => {
const traceId = generateTraceId()
return request(url, {
...options,
headers: {
...options.headers,
'X-Trace-Id': traceId
}
})
}
在电商后台项目中,这套请求层架构每天处理超过300万次API调用,错误率控制在0.2%以下。最让我自豪的不是技术实现本身,而是当业务方提出新需求时,我们能在请求层快速实现非侵入式的解决方案——比如上周新增的请求重试机制,只用了15行代码就全局生效。