使用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
相关产品推荐
相关产品推荐

