Sto cercando di creare una classe che gestisca le mie chiamate di rete per il mio progetto. Per ora, intendo gestire gli errori a livello globale, tutto andava bene. Ho creato due funzioni; per le richieste di posta postRequest(:_)
e per ottenere le richieste getRequests(:_)
. Le funzioni Datamaker consentono di restituire dati come URL, parametri, intestazioni ecc., Funzioni del datapander per analizzare i dati di risposta e infine una funzione per risolvere gli errori denominati errorHandler()
.Alamofire: come gestire 401 globalmente?
Quando chiamo quella di funzione di richiesta, fornisco un parametro per aiutare la funzione che deve essere richiesta. Nella funzione chiama i datamakers per ottenere i dati in primo luogo, quindi effettua una richiesta con Alamofire
e alla fine se la richiesta ha esito positivo chiama dataparser e onSuccess(data:)
oppure se non lo è chiama errorHandler(statusCode:)
e onFailure(message:)
.
Ho inserito un blocco di interruttori in errorHandler
e fornito il codice di stato per il suo parametro. In case 401
ho chiamato Token().refresh()
e nel suo completamento chiamato completamento errorHanlder
. Nel blocco di completamento ho chiamato di nuovo lo postRequest
con gli stessi parametri. Non ha funzionato. Non so perché, è andato in loop infinito ogni volta e fatto richieste consecutivamente.
Quindi ho deciso di provare la classe AuthorizationManager
(disponibile in questo collegamento; Alamofire : How to handle errors globally). L'ho modificato un po '(ho aggiunto un nuovo parametro come intestazioni e modificato il tipo NetworkSuccessHandler
in NSData
). Ecco la nuova forma:
public class AuthorizationManager: Manager {
public typealias NetworkSuccessHandler = (NSData?) -> Void
public typealias NetworkFailureHandler = (NSHTTPURLResponse?, AnyObject?, NSError) -> Void
private typealias CachedTask = (NSHTTPURLResponse?, AnyObject?, NSError?) -> Void
private var cachedTasks = Array<CachedTask>()
private var isRefreshing = false
public func startRequest(
method method: Alamofire.Method,
URLString: URLStringConvertible,
parameters: [String: AnyObject]?,
encoding: ParameterEncoding,
headers: [String:String]?,
success: NetworkSuccessHandler?,
failure: NetworkFailureHandler?) -> Request?
{
let cachedTask: CachedTask = { [weak self] URLResponse, data, error in
guard let strongSelf = self else { return }
if let error = error {
failure?(URLResponse, data, error)
} else {
strongSelf.startRequest(
method: method,
URLString: URLString,
parameters: parameters,
encoding: encoding,
headers: headers,
success: success,
failure: failure
)
}
}
if self.isRefreshing {
self.cachedTasks.append(cachedTask)
return nil
}
// Append your auth tokens here to your parameters
let request = self.request(method, URLString, parameters: parameters, encoding: encoding, headers: headers)
request.response { [weak self] request, response, data, error in
guard let strongSelf = self else { return }
if let response = response where response.statusCode == 401 {
strongSelf.cachedTasks.append(cachedTask)
strongSelf.refreshTokens()
return
}
if let error = error {
failure?(response, data, error)
} else {
success?(data)
}
}
return request
}
func refreshTokens() {
self.isRefreshing = true
// Make the refresh call and run the following in the success closure to restart the cached tasks
Token().refresh {() ->() in
let cachedTaskCopy = self.cachedTasks
self.cachedTasks.removeAll()
cachedTaskCopy.map { $0(nil, nil, nil) }
self.isRefreshing = false
}
}
}
Chiamato nel mio postRequest
come:
func postRequest(requestType: postRequestType, additionalParameters: [String]?, onSuccess: onSuccessRequest = {_ in }, onFailure: onFailureRequest = {_ in }){
print("post")
let requestData = returnStaticDataForPostRequest(requestType, additionalParameters: additionalParameters)
let Manager = AuthorizationManager()
Manager.startRequest(method: .POST, URLString: requestData.0, parameters: requestData.2, encoding: requestData.3, headers: requestData.1, success: { (data) -> Void in
print("Manager")
let json = JSON(data: data!)
print(json)
dataParserForPostRequests(json, parseForWhat: requestType)
onSuccess(json: json)
}) { (response, message, error) -> Void in
print(error)
}
}
e l'uso del postRequests
nel ViewController
:
postRequest(.LOGIN, additionalParameters: ["asdasd", "asdasd"], onSuccess: { (json) ->() in
print(">>>login_try_succeeded")
self.performSegueWithIdentifier("LoginToMain", sender: self)
}) { (errorCode) ->() in
print(">>>login_try_failed(\(errorCode))")
}
Questo è lo stato corrente. Quando eseguo il codice e provo ad accedere a AuthorizationManager
non funziona. Stampa semplicemente;
post
E, infine, non so se è rilevante, ma non v'è giallo di avvertimento in questa linea:
cachedTaskCopy.map { $0(nil, nil, nil) }
dice "Result of call to 'map' is unused"
Per riassumere ho bisogno di capire come mi in grado di gestire 401 e so come utilizzare AuthorizationManager
in un modo diverso da questo.
EDIT:
ho provato la corsa del questo codice direttamente dal ViewController
ma non funziona affatto. È come se il codice fosse invisibile.
AuthorizationManager().startRequest(method: .POST, URLString: NSURL(string: "http://server.url/token")!, parameters: ["":""], encoding: .JSON,headers: ["":""], success: { (data) -> Void in
print(data)
}) { (response, data, error) -> Void in
print(error)
print("asdasd")
}
Questa non era la mia domanda, ma la tua risposta funzionerà effettivamente per l'ultima parte che ha spiegato come "EDIT" (o non ricordo quale sia la mia domanda in realtà è :)). Ad ogni modo, poiché è passato molto tempo da quando l'ho chiesto, ho iniziato a utilizzare Moya (https://github.com/Moya/Moya) che fornisce funzionalità davvero interessanti per sviluppare l'utilizzo pulito di Alamofire. Si discute su come gestire il 401 e gli altri codici di stato, in questo collegamento; https://github.com/Moya/Moya/issues/379. Comunque sembra che la tua risposta stia aumentando, presumo che sia utile per le persone. Quindi accetterò questo. – Faruk
Beh, spero che aiuti qualcuno! Inoltre, Moya è fantastica, felice che tu sia riuscito a trovare una soluzione. – tbogosia
Sì! Grazie per il vostro interesse ad aiutare :) – Faruk