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

使用Alamofire RequestInterceptor:非400-500响应码下触发重试及token过期处理

Alamofire RequestInterceptor 重试相关问题解答

一、除400-500响应码外,触发重试的其他方式

Alamofire的RequestInterceptor触发重试的逻辑完全可以自定义,不止局限于HTTP响应码区间,常见的触发方式有:

  • 基于业务错误判定:在retry(_:for:dueTo:)方法中,解析响应体里的业务错误码(比如接口返回JSON中的code字段),只要符合重试条件(如临时服务异常、参数校验可重试错误等),就返回.retry或.retry(withDelay:)。
  • 处理非HTTP类错误:针对网络超时、DNS解析失败、连接断开这类无HTTP状态码的错误,Alamofire会将其包装为AFError,你可以在retry方法中判断这类错误类型,主动触发重试。
  • 主动触发重试信号:在adapt(_:for:)方法中,如果提前检测到异常(比如本地token已过期、请求参数缺失),可以直接返回包含自定义错误的.failure,然后在retry方法中捕获该错误并触发重试。

二、服务器返回200但token过期的解决方案

这种场景下完全可以手动触发重试,也可以提前规避问题,具体方案如下:

1. 手动触发重试(响应阶段处理)

在retry方法中,先解析响应数据,判断业务错误码是否表示token过期,执行刷新token逻辑后触发重试:

func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
    // 解析响应体,检查token过期的业务码
    if let responseData = request.data,
       let responseJSON = try? JSONSerialization.jsonObject(with: responseData) as? [String: Any],
       let businessCode = responseJSON["code"] as? Int,
       businessCode == 1001 { // 假设1001是token过期的业务码
        
        // 调用刷新token的异步接口
        refreshToken { [weak self] newToken in
            guard let self = self, let token = newToken else {
                completion(.doNotRetry)
                return
            }
            // 保存新token,后续请求自动复用
            UserDefaults.standard.set(token, forKey: "auth_token")
            // 触发重试
            completion(.retry)
        }
        return
    }
    
    // 其他重试逻辑...
    completion(.doNotRetry)
}

2. 提前规避(请求适配阶段处理)

在adapt方法中提前检查本地token的有效期,若已过期或即将过期,先刷新token再发起请求,避免走到响应阶段:

func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    guard let currentToken = UserDefaults.standard.string(forKey: "auth_token"),
          !isTokenExpired(currentToken) else {
        // token过期,先执行刷新逻辑
        refreshToken { [weak self] newToken in
            guard let self = self, let token = newToken else {
                completion(.failure(NSError(domain: "TokenError", code: -1, userInfo: [NSLocalizedDescriptionKey: "刷新token失败"])))
                return
            }
            var adaptedRequest = urlRequest
            adaptedRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            completion(.success(adaptedRequest))
        }
        return
    }
    
    // token有效,直接适配请求
    var adaptedRequest = urlRequest
    adaptedRequest.setValue("Bearer \(currentToken)", forHTTPHeaderField: "Authorization")
    completion(.success(adaptedRequest))
}

// 辅助方法:判断JWT格式token是否过期
private func isTokenExpired(_ token: String) -> Bool {
    guard let payload = token.components(separatedBy: ".").dropFirst().first,
          let data = Data(base64Encoded: payload.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")),
          let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
          let exp = json["exp"] as? TimeInterval else {
        return true
    }
    return Date().timeIntervalSince1970 > exp
}

3. 统一错误转换

可以在响应处理环节,将业务错误码转换为自定义Error类型,然后在retry方法中捕获该Error并触发重试,让逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 08:47:28