You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native开关飞行模式后Axios请求长时间无响应问题咨询

问题根因
  • 全局固定cancelToken配置错误:创建Axios实例时绑定了静态单例cancel token,所有请求共用同一个token上下文,断网期间堆积的请求无法被独立回收,会持续占用请求通道。
  • Axios原生timeout存在生效盲区:该超时计时仅在TCP连接正常建立后才会启动,断网状态下连接处于半开、SYN重传、DNS缓存失效的阶段时,timeout不会触发,会一直等待系统网络栈返回结果。
  • 移动端系统网络栈不会自动清理断网期间堆积的失效连接:重连后旧的失效连接会占满连接池配额,新发起的请求只能排队等待,必须等旧请求全部超时(系统层TCP超时默认可能长达几十秒到数分钟)才会释放通道,这也是强杀应用才能恢复的核心原因——强杀会直接清空整个连接池和pending请求队列。
修复方案

1. 修正cancelToken的错误用法

禁止在Axios实例级别绑定固定的全局cancelToken,否则任意一个请求触发取消都会导致所有绑定该token的请求被中断,这也是当前配置里的明显bug。移除实例级别的固定cancelToken配置,改为每个请求独立生成cancelToken,避免单token失效拖垮所有请求:

// 修正后的Axios实例配置,移除全局固定cancelToken
export const axiosInstance = api.create({
  baseURL: BASE_URL,
  timeout: 10000,
  headers: {
    source: API_SOURCE,
    apiVersion: API_VERSION,
    'Content-Type': 'application/json',
  },
})

2. 监听网络状态,重连时主动清理堆积请求

通过网络状态监听,在离线切回在线的节点主动清空所有pending状态的旧请求,避免失效请求占用连接池:

let isOffline = false
const pendingRequests = new Map()

// 请求拦截器:为每个请求绑定独立cancelToken,记录pending队列
axiosInstance.interceptors.request.use(config => {
  const source = axios.CancelToken.source()
  config.cancelToken = source.token
  pendingRequests.set(`${config.method}_${config.url}`, source)

  // 重连后增加短延迟,等系统网络栈完成初始化再发请求
  if (isOffline) {
    return new Promise(resolve => setTimeout(() => {
      config.headers['Connection'] = 'close' // 禁用持久连接复用,避免拿到失效连接
      resolve(config)
    }, 200))
  }

  config.headers['Connection'] = 'close'
  return config
})

// 响应拦截器:请求结束后从pending队列移除
axiosInstance.interceptors.response.use(
  response => {
    pendingRequests.delete(`${response.config.method}_${response.config.url}`)
    return response
  },
  error => {
    if (error.config) {
      pendingRequests.delete(`${error.config.method}_${error.config.url}`)
    }
    return Promise.reject(error)
  }
)

// 绑定网络状态监听
window.addEventListener('offline', () => {
  isOffline = true
})
window.addEventListener('online', () => {
  // 重连瞬间取消所有堆积的旧请求
  pendingRequests.forEach(source => source.cancel('网络重连,取消过期请求'))
  pendingRequests.clear()
  isOffline = false
})

3. 增加双重超时兜底,覆盖Axios timeout盲区

用Promise.race实现从请求发起瞬间就开始计时的兜底超时,解决连接建立阶段timeout不生效的问题:

/**
 * 带全链路超时兜底的请求包装
 * @param {Promise} requestPromise 原始请求Promise
 * @param {number} timeout 超时时长,默认10s
 */
const withTimeout = (requestPromise, timeout = 10000) => {
  return Promise.race([
    requestPromise,
    new Promise((_, reject) => {
      setTimeout(() => reject(new Error('REQUEST_TIMEOUT')), timeout)
    })
  ])
}

// 业务请求改造示例
async testApiCall(params: { status: boolean; set?: boolean }, state) {
  try {
    const { status, set = true } = params
    console.log('before call')
    const result = (await withTimeout(setStatus({
      online: status
    }))) as any
    console.log('after call', result)
    return result
  } catch (error) {
    // 被取消/超时的请求可自动重试1次,避免偶发失败
    if (axios.isCancel(error) || error.message === 'REQUEST_TIMEOUT') {
      return withTimeout(setStatus({ online: status }))
    }
    return error
  }
}

4. 混合开发场景额外优化

如果是App内嵌WebView场景,可协调原生端在网络重连、飞行模式切换时,主动清空WebView网络缓存、重置网络连接池,从底层规避失效连接残留问题。

内容的提问来源于stack exchange,提问作者Riku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:51:23