如何在Alamofire中全局处理错误?解决410状态码重试两次问题
解决Alamofire中410错误全局处理重复触发的问题
针对你遇到的RequestInterceptor的retry方法被调用两次的问题,这里有几个更合适的Alamofire钩子方案,无需在更高层级手动处理:
1. 使用EventMonitor(推荐)
EventMonitor是Alamofire专门用于监听请求生命周期事件的扩展点,每个请求完成时只会触发一次错误回调,完全避免重复执行的问题。你可以实现它的requestDidComplete(_:with:)方法来检测410错误并执行重置操作:
class SessionExpiryMonitor: EventMonitor { func requestDidComplete(_ request: Request, with error: Error?) { guard let afError = error as? AFError, case .responseValidationFailed(.unacceptableStatusCode(410)) = afError else { return } // 执行数据重置、UI刷新逻辑 resetAppUserData() triggerLoginRedirect() } private func resetAppUserData() { // 这里写重置用户数据的代码,比如清空本地缓存、用户信息 } private func triggerLoginRedirect() { // 触发UI重置,比如发送通知跳转登录页、重置导航栈 } } // 初始化Session时添加这个Monitor let expiryMonitor = SessionExpiryMonitor() let session = Session(eventMonitors: [expiryMonitor])
2. 自定义ResponseSerializer
如果希望在响应序列化阶段处理410错误,可以自定义全局响应序列化器,在序列化过程中检测错误并执行操作:
class ExpiryHandlingJSONSerializer: JSONResponseSerializer { override func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any { if let afError = error as? AFError, case .responseValidationFailed(.unacceptableStatusCode(410)) = afError { // 执行重置操作 resetAppUserData() triggerLoginRedirect() } return try super.serialize(request: request, response: response, data: data, error: error) } private func resetAppUserData() { /* 重置逻辑 */ } private func triggerLoginRedirect() { /* UI重置逻辑 */ } } // 给Session设置全局序列化器 let session = Session(responseSerializer: ExpiryHandlingJSONSerializer())
注意:如果你的项目用到多种序列化器(比如JSON、Plain Text),需要为每种序列化器单独处理,通用性不如EventMonitor。
3. 调整RetryInterceptor逻辑(如果坚持用Interceptor)
如果还是想用RequestInterceptor,可以通过给Request添加关联对象标记,确保410错误只被处理一次:
private var handledExpiryKey = "HandledExpiryKey" extension Request { var hasHandledExpiry: Bool { get { objc_getAssociatedObject(self, &handledExpiryKey) as? Bool ?? false } set { objc_setAssociatedObject(self, &handledExpiryKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } class ExpiryRetryInterceptor: RequestInterceptor { func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { guard let afError = error as? AFError, case .responseValidationFailed(.unacceptableStatusCode(410)) = afError, !request.hasHandledExpiry else { completion(.doNotRetry) return } request.hasHandledExpiry = true // 执行重置操作 resetAppUserData() triggerLoginRedirect() completion(.doNotRetry) } private func resetAppUserData() { /* 重置逻辑 */ } private func triggerLoginRedirect() { /* UI重置逻辑 */ } }
这种方法需要处理关联对象的线程安全问题,相对繁琐,但能解决当前retry方法重复调用的问题。
内容的提问来源于stack exchange,提问作者urSus
相关产品推荐
相关产品推荐

