Alamofire请求重试机制和更新token

1. 应用场景

发送网络请求时,一些请求失败后需要自动重试。大多数情况下,在重试前需要做一些操作,比如更新参数,更新 token 等。
本文对应的真实场景: 发送请求 -> 返回401 -> 更新 token -> 重新请求

如果不知道 Alamofire 提供了 retrier 机制,你很有可能想到在每一个请求的失败返回中手动重试,千万不要。下面详细介绍怎样利用 Alamofire 便捷地实现重试。

2. Alamofire 的 RequestInterceptor

RequestInterceptor 是一个协议,其中包含了 RequestAdapter 和 RequestRetrier 两个协议。

2.1 RequestAdapter

暂且翻译成”适配器“吧。
这个协议只有一个函数:

func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void)

它可以让你在请求真正发起前,做一些预处理。比如给某些特定函数做重定向、添加一些 header,或者阻拦某些请求。
本文真实场景:给一个特定请求添加一个用于身份验证的 token。

2.1 RequestRetrier

翻译成”重试器“吧。
这个协议也只有一个函数:

func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

实现这个函数的时候,可以通过执行函数的 completion 闭包来决定是否需要重试。
所以,在这个函数实现中,我们只要去判断出需要重试的条件,然后执行 completion(.retry),一旦请求有错误返回,就会进入这个函数,重试就触发了。

3. 代码示例

// 新建一个自定义Interceptor, 遵从 RequestInterceptor 协议
class GenericRequestInterceptor: RequestInterceptor {
	func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var request = urlRequest
        //Just for gatway host
        guard let baseUrl = gatewayBaseUrl, !accessToken.isEmpty else {
            return completion(.success(request))
        }
        if let urlString = urlRequest.url?.absoluteString, urlString.hasPrefix(baseUrl) {
             // set JWT token to request header
            request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
        }

        completion(.success(request))
    }
    
    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
            completion(.doNotRetry)
            return
        }
        
        // 确保只重试一次,否则就无限重试下去了
        guard request.retryCount == 0, let baseUrl = gatewayBaseUrl else { return completion(.doNotRetry) }
        
        // 如果是特定 URL 并且状态码是 401
        if let urlString = request.firstRequest?.url?.absoluteString, urlString.hasPrefix(baseUrl) {
        	// 重新获取 token
            gatewayAuthService?.refreshJWT(createURLRequest: createURLRequestFunc, complete: {[weak self] accessToken in
                if !accessToken.isEmpty {
                	// 保存新的 token,重试的时候在 adapter 中使用
                    self?.accessToken = accessToken
                    // 重试
                    completion(.retry)
                } else {
                    completion(.doNotRetry)
                }
            })
        } else {
            completion(.doNotRetry)
        }
    }
}

然后在初始化 Session 的时候, 把这个自定义 GenericRequestInterceptor 设置给 Session。

sessionManager = Session(configuration: sessionConfig, interceptor: GenericRequestInterceptor())

这样,如果请求失败,就会触发重试。

4. 小心有坑

本文肯定不仅仅是一个基础教程啦,否则就没意思了。
且看!
如果你发起的是一个错误请求,比如 “https://www.balabalabala.com”, 很快会进入 retrier 函数。
但是,如果请求返回诸如 401 的状态码,它是不会进入 retrier 函数滴。为什么呢?
这是 Alamofire 文档里的一句话:

Response Validation
By default, Alamofire treats any completed request to be successful, regardless of the content of the response.

意思是,像 401 这种返回,按照请求成功处理。所以不会触发 Retrier.
那怎么办呢?
validate()
这个东西可以让你在 response 之前,对特定状态码返回错误。就是你可以在这个里面让 401 当做错误返回。

return sessionManager.request(urlRequest).validate({ request, response, data in
            let statusCode = response.statusCode
            if statusCode != 401 {
                return .success(())
            } else {
                return .failure(AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401)))
            }
        }) .response(queue: workerQueue, completionHandler: { [weak self] dataResponse in

		}

这样,遇到 401 就可以进入 Retrier 了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
证书机制Token机制是两种不同的身份验证和授权机制,它们各自的原理和优缺点如下所示: 证书机制: - 原理:证书机制基于公钥加密和数字签名技术。在证书机制中,通信实体使用数字证书来验证其身份,并确保通信的安全性。证书包含了公钥、数字签名和证书主体等信息。证书由认证机构(CA)颁发,CA使用自己的私钥对证书进行签名。在通信过程中,接收方使用CA的公钥来验证证书的签名和有效性,从而确认通信实体的身份。 - 优点: 1. 强身份验证:证书机制提供了强大的身份验证,通过验证证书的签名和有效性,可以确保通信实体的身份是可信的。 2. 数据保护:证书机制使用公钥加密算法来加密通信中的数据,保护数据的机密性。 3. 完整性保护:证书机制使用数字签名来验证数据的完整性,防止数据被篡改。 - 缺点: 1. 复杂性:证书机制涉及到证书颁发、验证和管理等复杂的过程,需要依赖认证机构和密钥管理。 2. 依赖第三方:证书机制需要依赖认证机构(CA)来颁发和验证证书,因此对于自建系统或小规模系统可能存在依赖性和成本问题。 Token机制: - 原理:Token机制基于令牌的授权方式。在Token机制中,用户通过提供有效的令牌来进行身份验证和授权。令牌通常包含了用户身份信息和访问权限等相关信息。在用户登录成功后,服务器会生成一个令牌,并发送给客户端。客户端在后续请求中携带该令牌进行身份验证和授权。 - 优点: 1. 简单性:Token机制相对于证书机制而言更加简单,不需要依赖认证机构和密钥管理。 2. 可扩展性:Token机制可以支持跨多个系统或服务的身份验证和授权,适用于分布式系统和微服务架构。 3. 离线验证:Token机制可以在服务器无需实时验证的情况下进行离线验证,提高了性能和可伸缩性。 - 缺点: 1. 安全性:Token机制在传输过程中,如果没有使用安全的通信通道,可能会被截获或篡改,因此需要注意保护令牌的安全性。 2. 有效期管理:Token机制需要管理令牌的有效期,以及令牌的刷新和撤销等操作,增加了一定的管理复杂性。 综合而言,证书机制提供了强大的身份验证和数据保护机制,适用于对安全性要求较高的场景;而Token机制相对简单且具有较好的可扩展性,适用于分布式系统和无状态服务的身份验证和授权。选择适当的机制应基于具体的应用场景和安全需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值