2016-03-17 15 views
8

Tôi đang cố gắng xây dựng một lớp quản lý các cuộc gọi mạng cho dự án của mình. Đến thời điểm này, tôi có nghĩa là xử lý lỗi trên toàn cầu, mọi thứ đều ổn. Tôi đã tạo ra hai chức năng; đối với yêu cầu gửi bài đăng postRequest(:_) và để nhận yêu cầu getRequests(:_). Datamaker có chức năng trả về dữ liệu như URL, tham số, tiêu đề, vv, các hàm dataparser để phân tích cú pháp phản hồi và cuối cùng là một hàm để giải quyết các lỗi được gọi là errorHandler().Alamofire: Làm thế nào để xử lý 401 toàn cầu?

Khi tôi gọi một hàm yêu cầu, tôi cung cấp thông số để giúp chức năng yêu cầu. Trong hàm, nó gọi các nhà lập trình để lấy dữ liệu trước hết, sau đó yêu cầu với Alamofire và cuối cùng nếu yêu cầu thành công, nó gọi dataparser và onSuccess(data:) đóng hoặc nếu nó không phải là yêu cầu errorHandler(statusCode:)onFailure(message:) đóng.

Tôi đặt khối chuyển đổi trong errorHandler và đã cung cấp mã trạng thái cho thông số của nó. Trong số case 401 Tôi gọi là Token().refresh() và hoàn thành được gọi là hoàn thành errorHanlder. Trong khối hoàn thành của postRequest/errorHandler, tôi gọi lại là postRequest với cùng thông số. Nó không hoạt động. Tôi không lý do tại sao, nó đã đi vào vòng lặp vô hạn mọi lúc và yêu cầu liên tục.

Vì vậy, tôi quyết định thử cnoon 's AuthorizationManager lớp (có thể được tìm thấy trong liên kết này; Alamofire : How to handle errors globally). Tôi đã thay đổi nó một chút (thêm thông số mới làm tiêu đề và thay đổi loại của NetworkSuccessHandler thành NSData). Dưới đây là hình thức mới:

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

gọi nó trong tôi postRequest như:

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

} 

Và sử dụng postRequests trong 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))") 
     } 

Đây là trạng thái hiện tại. Khi tôi chạy mã và cố gắng đăng nhập AuthorizationManager không hoạt động. Nó chỉ in;

post 

Và cuối cùng, tôi không biết nếu nó có liên quan nhưng có cảnh báo màu vàng tại dòng này:

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

nói "Result of call to 'map' is unused"

Tóm lại tôi cần phải tìm ra cách tôi có thể xử lý 401 và tôi biết cách sử dụng AuthorizationManager theo cách khác.

EDIT:

Tôi cố gắng chạy mã này trực tiếp từ ViewController nhưng nó không làm việc ở tất cả. Nó giống như mã là vô hình.

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

Trả lời

2

Có thể là trường hợp người quản lý ủy quyền của bạn không bền bỉ sau lần gửi yêu cầu ban đầu.

Thông thường đó là thực hành tốt để tránh những Singleton pattern, nhưng đây không phải là một trường hợp xấu cho nó:

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

Và khi gọi yêu cầu của bạn, sử dụng Ví dụ singleton này chứ không phải là instantiating một AuthorizationManager mới như

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

Tôi đoán đây có thể là vấn đề, vì khi bạn tạo AuthorizationManager trong cả hai trường hợp, không có gì chủ động giữ lại đối tượng đó. Người quản lý có thể được tạo, chạy yêu cầu và sau đó được deallocated trước cachedTask hoặc thậm chí trước khi xử lý hoàn thành, trong trường hợp này, guard let strongSelf = self else { return } của bạn sẽ trở về mà không cần chạy bất kỳ phần hoàn thành nào của bạn hoặc cachedTasks.

Hy vọng điều đó sẽ hữu ích. Nếu điều đó vấn đề, thì giải pháp singleton đó phải rất đơn giản.

+0

Đó không phải là câu hỏi của tôi nhưng câu trả lời của bạn sẽ thực sự hoạt động cho phần cuối được giải thích là 'EDIT' (hoặc tôi không nhớ câu hỏi của tôi là gì :)). Dù sao, vì đã có rất nhiều thời gian trôi qua kể từ khi tôi hỏi điều này, tôi đã bắt đầu sử dụng Moya (https://github.com/Moya/Moya) cung cấp các tính năng thực sự tốt đẹp để phát triển việc sử dụng sạch Alamofire. Nó được thảo luận làm thế nào để xử lý 401, và các mã trạng thái khác, trong liên kết này; https://github.com/Moya/Moya/issues/379. Tuy nhiên có vẻ như câu trả lời của bạn là nhận được upvotes, tôi cho rằng nó rất hữu ích cho mọi người. Vì vậy, tôi sẽ chấp nhận điều này. – Faruk

+0

Vâng, hy vọng nó sẽ giúp một ai đó! Ngoài ra, Moya là tuyệt vời, vui mừng bạn đã có thể tìm ra một giải pháp. – tbogosia

+0

Vâng! Cảm ơn bạn đã quan tâm giúp :) – Faruk

Các vấn đề liên quan