我在代码中有很多地方处理Alamofire请求/响应。
由于某些间歇性问题(最常见的是片状网络),每个请求都可能失败。
我希望能够在拯救之前重试请求3次。
直截了当的方法就是拥有类似的东西
var errorCount = 0
func requestType1() {
let request = Alamofire.request(...).responseJSON { response in
if (isError(response) && errorCount < 3) {
errorCount += 1
request1()
}
if (isError(response)) {
handleError()
}
handleSuccess()
}
}
但是,出于多种原因,我不喜欢这种方法。最明显的是我需要为每个请求类型实现这样的代码(我有15个这样的代码)。
我很好奇是否有办法做某些事情(变化很小且非侵入性)
let request = Alamofire.request(..., **3**)
答案 0 :(得分:21)
Alamofire 4.0有一个RequestRetrier
协议可以使用。
示例:
class OAuth2Handler: RequestAdapter, RequestRetrier {
public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: RequestRetryCompletion) {
if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 {
completion(true, 1.0) // retry after 1 second
} else {
completion(false, 0.0) // don't retry
}
// Or do something with the retryCount
// i.e. completion(request.retryCount <= 10, 1.0)
}
}
let sessionManager = SessionManager()
sessionManager.retrier = OAuth2Handler()
sessionManager.request(urlString).responseJSON { response in
debugPrint(response)
}
答案 1 :(得分:4)
我遇到了同样的问题,我收到了使用RequestRetrier
,should
方法和request.retryCount
重试的请求。喜欢它的东西:
// MARK: - RequestRetry
public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
lock.lock() ; defer { lock.unlock() }
if let response = request.task?.response as? HTTPURLResponse{
if response.statusCode == 401 {
requestsToRetry.append(completion)
getToken { (expires, _) in
_ = SessionCountdownToken.sharedInstance.startCount(expirationTime: expires)
}
} else {
if request.retryCount == 3 { completion(false, 0.0 ); return}
completion(true, 1.0)
return
}
} else {
completion(false, 0.0)
}
}
答案 2 :(得分:3)
你使用Swift获得的一些语法糖就是你可以使用它:
public func updateEvents(someNormalParam: Bool = true, someBlock: (Void->Void))
像这样:
updateEvents(someNormalParam: false) {...}
请注意,该块位于updateEvents函数的()之外,与您通常所期望的相反。它只有在块是函数声明中的最后一件事时才有效。
这意味着如果您碰巧遇到了诸如Alamofire请求之类的阻止,您可以使用重试功能有效地将其包装起来。一个稍微复杂的问题是你想在块内调用一个块。没什么大不了的:
func retryWrapper(alamoBlock: (Void->Request)) {
alamoblock().responseJSON() {
//Your retry logic here
}
}
你这样使用它:
retryWrapper() {
Alamofire.request(method, targetUrl, parameters: parameters, encoding: encoding)
}
意思是你要做的就是找到你的Alamofire调用并将它们包装在{}中并放入retryWrapper()之前。重试逻辑本身只有一次。
答案 3 :(得分:1)
我已经创建了一个包装类,用于请求重试器应该起作用。 https://gist.github.com/daljeetseera/7ce2b53b8a88d8a5e9b172c0495c6455
并在请求所需的会话管理器中使用了请求重试器。
static let sharedManager: SessionManager = {
let configuration = URLSessionConfiguration.default
let manager = Alamofire.SessionManager(configuration: configuration)
let requestRet = NetworkRequestRetrier()
manager.retrier = requestRet
return manager
}()
答案 4 :(得分:-4)
我所做的就是以下内容,如果请求失败,我会向发出请求的人发送失败的通知。然后它负责重试请求。发现这更容易。
Alamofire.request(.GET, urlString, parameters: params, headers: defaultHeaders)
.validate()
.responseJSON
{
response in
switch response.result
{
case .Success:
print("Request Successful")
let json = JSON(data:response.data!)
NSNotificationCenter.defaultCenter().postNotificationName(SUCCESS_NOTIFICATION, object: movieArray)
case .Failure(let error):
print("Request Failed with error \(error)")
NSNotificationCenter.defaultCenter().postNotificationName(FAILURE_NOTIFICATION, object: error)
}
}