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

React Native对接.NET后端刷新token偶发旧token复用及状态码0问题求助

问题背景

我有一个React Native应用,通过微软基于token的身份验证与.NET Framework后端(Web API)通信。token有效期为30分钟,过期后首次调用接口时服务端会返回401,此时会调用刷新token接口生成新的刷新token供应用使用。等待刷新token返回的过程中,客户端会将其他请求入队,拿到新token后再用新token重新发起这些请求。

疑难问题

服务端有时会返回状态码0,暂时未定位到根因。同时观察到的规律是:调用刷新token接口时,后端会删除旧token并生成新token,但应用发起新接口请求时有时仍使用旧token而非新token,该问题不是必现。是否是队列中的请求未成功入队,或是入队逻辑存在问题?

技术栈
  • 服务端:4台运行IIS 10的专用服务器,通过负载均衡器分发请求
  • 前端:React Native 0.64.2版本,采用react-native-ssl-pinning发起请求
相关代码

基础请求方法

async request(route: string,
    action: string,
    params: any = null,
    isJson: boolean = true,
  ) {
    var options = await this.handleOption(action, params, isJson)

    route = Config.API_BASE_URI + route
    
    return new Promise(async resolve => {
      try {
        var response = await fetchSSLPinning(route, options)
        return resolve(response)
      } catch (e) {
        // // console.log(e)
        var originalRequest = {
          route,
          options,
        }
        var p = this.handleError(e, originalRequest)
        return resolve(p)
      }
    })
    },

错误处理逻辑

async handleError(error: any, originalRequest: any): Promise<any> {
    const errorResponse = error

    if (this.isTokenExpiredError(errorResponse)) {
      return this.resetTokenAndReattemptRequest(error, originalRequest)
    }
    this.dispatchError(true, errorResponse.status)
    return Promise.reject(error)
    },

刷新token并重试逻辑

async resetTokenAndReattemptRequest(error: any, originalRequest: any) {
    try {
      
      const resetToken = await TokenStorage.getToken() 
      if (!resetToken) {
        return Promise.reject(error)
      }

     
      const retryOriginalRequest = new Promise(resolve => {
        this.addSubscriber((accessToken: string) => {
          var options = {
            ...originalRequest.options,
            headers: {
              ...originalRequest.options.headers,
              authorization: 'Bearer ' + accessToken,
            },
          }
         
          resolve(fetchSSLPinning(originalRequest.route, options))
        })
      })
      if (!this.isAlreadyFetchingAccessToken) {
        this.isAlreadyFetchingAccessToken = true
        const refreshToken = await TokenStorage.getRefreshToken()
        const userName = await TokenStorage.getUsername()

        const response = await AuthenticationService.refreshToken(
          refreshToken,
          userName,
        )

        if (!response) {
         
          this.isAlreadyFetchingAccessToken = false
          this.dispatchError(true, '404')
          return Promise.reject(error)
        }
        
        await TokenStorage.storeTokenInfo(
          response.access_token,
          response.refresh_token,
          response.userName,
        ) // save the newly refreshed token for other requests to use

        const newToken = response.access_token
        this.isAlreadyFetchingAccessToken = false
        this.onAccessTokenFetched(newToken)
      }
      return retryOriginalRequest
    } catch (err) {
      
      this.isAlreadyFetchingAccessToken = false
      this.dispatchError(true, err.status)
      return Promise.reject(err)
    }
  },

订阅者回调执行逻辑

onAccessTokenFetched(accessToken: string) {
    // When the refresh is successful, we start retrying the requests one by one and empty the queue
    this.subscribers.forEach((callback: any) => {
      callback(accessToken)
    })
    this.subscribers = []
  },
问题排查与解决方案

偶发旧token请求问题修复

现有代码存在2个核心隐患点:

  1. 刷新token过程中新增的请求未加锁:handleOption方法获取token时,没有判断当前是否处于token刷新中,刷新过程中发起的新请求会直接从本地存储拿到旧token发起请求,不会走错误处理入队逻辑,这就是偶发旧token请求的最常见原因。
    修复方案:在handleOption获取token前判断this.isAlreadyFetchingAccessToken状态,如果为true,直接将该请求加入订阅队列,不要直接用旧token发起请求。
  2. isAlreadyFetchingAccessToken变量无原子性保护:多个异步请求同时触发401时,可能会同时进入resetTokenAndReattemptRequest,出现重复刷新token的问题,旧token被删除后,后触发的刷新请求用已失效的refreshToken调用接口会失败,导致后续队列请求也用旧token。
    修复方案:将isAlreadyFetchingAccessToken的赋值操作放在订阅队列逻辑之前,确保第一个401请求进入后立刻锁定状态,后续请求直接入队。

状态码0问题排查

状态码0通常是跨域、网络中断、SSL证书验证失败、请求被拦截或者负载均衡超时导致的:

  1. 先排查负载均衡的会话保持配置:如果你的token验证是单节点内存存储,没有做分布式session共享,刷新token的请求落到A节点删除旧token,后续旧token请求落到B节点,就会出现偶发的验证失败或者异常响应。建议确认负载均衡是否开启了会话保持,或者后端token存储是否换成分布式缓存(如Redis)。
  2. 排查react-native-ssl-pinning的证书配置:如果证书链不完整,或者证书更新后客户端没有同步,会出现偶发的SSL握手失败,返回状态码0。
  3. 检查IIS的请求超时配置:如果刷新token接口的处理时间超过IIS或者负载均衡的超时阈值,会被主动断开连接,返回状态码0。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:57:03