合理超时时间需按接口类型区分:login设15s、uploadFile设120s、getBannerList设3s;仅通过uni.request的timeout字段设置,且只对当前请求生效。

uni-app 请求超时时间怎么设才合理?
默认情况下,uni.request 在 App 端(iOS/Android)的超时时间是 60 秒,但弱网下等 60 秒毫无意义——用户早划走了。关键不是“能不能设”,而是“设多少、在哪设”。
- 超时时间必须按接口类型区分:
login可设 15s,uploadFile可能得 120s,而getBannerList3s 就该失败重试 - 不要全局改
uni.setStorageSync('requestTimeout', ...)—— uni-app 没这 API,这是常见误解 - 真实生效的只有每个
uni.request调用里的timeout字段,且只对当前请求有效
uni.request({
url: '/api/user',
timeout: 8000, // 弱网下建议 5–10s,别写 60000
success: res => { /* ... */ },
fail: err => {
if (err.errMsg?.includes('timeout')) {
// 这里才是超时判断的可靠依据
}
}
})
App 端重试逻辑为什么不能只靠 catch?
uni.request 的 fail 回调在超时、网络中断、SSL 错误等场景都会触发,但「是否值得重试」得看错误类型:
- ✅ 可重试:网络断开(
Network Error)、超时(request:fail timeout)、502/503/504 - ❌ 不该重试:401(token 过期)、400(参数错)、404(路径不存在)、证书错误(iOS 会报
net::ERR_CERT_AUTHORITY_INVALID)
常见错误现象:封装了个「自动重试 3 次」的函数,结果用户输错密码,后端返回 401,前端连发 3 次登录请求,账号被锁。
重试前必须检查:
-
err.errMsg是否包含timeout或Network Error -
err.statusCode是否在[502, 503, 504]范围内(注意:App 端statusCode在fail中不一定存在,得靠err.errMsg主动识别) - 当前是否已处于离线状态(可用
uni.getNetworkType+ 监听uni.onNetworkStatusChange辅助判断)
怎么封装一个不侵入业务代码的重试机制?
核心思路:不改 uni.request 原方法,而是用代理函数包裹,支持配置化重试策略。
- 用高阶函数生成带重试能力的请求函数,比如
createRetryRequest({ maxRetry: 2, delay: 1000 }) - 重试间隔建议用指数退避:
delay * (2 ** retryCount),避免雪崩 - 必须加防抖控制:同一 URL + 参数组合 5 秒内重复触发,只保留最后一次(尤其防列表下拉刷新狂点)
const retryRequest = (options) => {
const { url, data, maxRetry = 2, delay = 1000 } = options
let retryCount = 0
<p>const attempt = () => {
return uni.request({
...options,
timeout: options.timeout || 8000,
fail: (err) => {
const isTimeout = /timeout/i.test(err.errMsg)
const isNetworkErr = /Network Error/i.test(err.errMsg)
if (retryCount </p>
App 端弱网重试最容易被忽略的三个点
- iOS WKWebView 下,某些证书错误或 DNS 解析失败不会进
fail,而是直接卡住或静默失败——必须配合 uni.showLoading + 定时器兜底(比如 12s 无响应就主动 reject)
- Android 上,后台切前台时,部分机型(尤其华为、小米)会清空 DNS 缓存,首次请求必慢,这不是超时,是系统行为;可提前在 onShow 里发个轻量探测请求预热
- 所有重试都应带唯一 traceId,并打日志(
console.log([retry:${traceId}] ${url} #${retryCount})),否则线上出问题根本分不清是网络抖动还是服务端反复失败
fail,而是直接卡住或静默失败——必须配合 uni.showLoading + 定时器兜底(比如 12s 无响应就主动 reject)console.log([retry:${traceId}] ${url} #${retryCount})),否则线上出问题根本分不清是网络抖动还是服务端反复失败重试不是万能解药,它掩盖不了接口设计缺陷。比如一个要 8 秒才能返回的详情页接口,再怎么重试也救不回体验——该拆分的接口、该加骨架屏的地方,绕不开。










