ios – Alamofire:如何在全球范围内处理401?

我正在尝试构建一个管理我的项目的网络调用的类.到目前为止,我的意思是在全球范围内处理错误,一切都很好.我创建了两个函数;对于post请求postRequest(:_)和get请求getRequests(:_). Datamaker用于返回数据,如URL,参数,标题等,数据解析器函数用于解析响应数据,最后用于解决称为errorHandler()的错误函数.

当我调用请求函数时,我给出一个参数来帮助它应该做出哪个请求.在函数中,它首先调用数据制作者获取数据,然后使用Alamofire发出请求,最后如果请求成功,则调用dataparser和onSuccess(data :)闭包,如果不是,则调用errorHandler(statusCode :)和onFailure(消息:)关闭.

我在errorHandler中放了一个switch块,并为其参数提供了statusCode.在401的情况下,我调用了Token().refresh()并在其中完成了名为errorHanlder的完成.在postRequest / errorHandler的完成块中,我使用相同的参数再次调用postRequest.它没用.我不知道为什么,它每次都进入无限循环并连续提出请求.

所以我决定尝试cnoon的AuthorizationManager类(可以在这链接中找到; Alamofire : How to handle errors globally).我稍微改了一下(添加一个新的参数作为标题,并将NetworkSuccessHandler的类型更改为NSData).这是新表格:

public class AuthorizationManager: Manager {
    public typealias NetworkSuccessHandler = (NSData?) -> Void
    public typealias NetworkFailureHandler = (NSHTTPURLResponse?,AnyObject?,NSError) -> Void

    private typealias CachedTask = (NSHTTPURLResponse?,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,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,headers:  headers)

            request.response { [weak self] request,response,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,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
        }
    }
}

在我的postRequest中调用它,如:

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)
    }

}

并在ViewController中使用postRequests:

postRequest(.LOGIN,additionalParameters: ["asdasd","asdasd"],onSuccess: { (json) -> () in
            print(">>>login_try_succeeded")        
            self.performSegueWithIdentifier("LoginToMain",sender: self)
            }) { (errorCode) -> () in
            print(">>>login_try_Failed(\(errorCode))")
        }

这是目前的状态.当我运行代码并尝试登录AuthorizationManager不起作用.它只是打印;

post

最后,我不知道它是否相关,但此行有黄色警告:

cachedTaskcopy.map { $0(nil,nil) }

说“调用’地图’的结果未使用”

总结一下,我需要弄清楚如何处理401,我知道如何以不同的方式使用AuthorizationManager.

编辑:

我尝试直接从ViewController运行此代码,但它根本不起作用.这就像代码是不可见的.

AuthorizationManager().startRequest(method: .POST,URLString: NSURL(string: "http://server.url/token")!,parameters: ["":""],encoding: .JSON,headers: ["":""],success: { (data) -> Void in
            print(data)
            }) { (response,error) -> Void in
                print(error)
                print("asdasd")
        }

解决方法

可能是您的AuthorizationManager在最初尝试发送请求后没有持久化的情况.

通常,避免使用单例模式是一种好习惯,但这不是一个不好的情况:

public class AuthorizationManager: Manager {
    static let shared = AuthorizationManager()
    // ...the rest of your class
}

调用您的请求时,请使用此单例实例,而不是实例化新的AuthorizationManager

AuthorizationManager.shared.startRequest(method: .POST,...etc...

我猜这可能是个问题,因为在这两种情况下创建AuthorizationManager时都没有主动保留该对象.可以创建管理器,运行请求,然后在cachedTask之前或甚至在完成处理之前解除分配,在这种情况下,你的后卫让strongSelf = self else {return}只返回而不运行任何完成或cachedTasks.

希望这会有所帮助.如果这是问题,那么单例解决方案应该非常简单.

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...