2015-03-13 22 views
12

Tôi có mã HTTP trong một bộ điều khiển AngularJS:Lỗi xử lý trong Alamofire

$http.post('/api/users/authenticate', {email: $scope.email, password: $scope.password}) 
    .success(function (data, status, headers, config) { 
     authService.login($scope.email); 
     $state.go('home'); 
    }) 
    .error(function (data, status, headers, config) { 
     $scope.errorMessages = data; 
     $scope.password = ""; 
    }); 

Trong trường hợp thành công, máy chủ sẽ trả lời với một đại diện JSON của người dùng. Trong trường hợp lỗi, máy chủ sẽ phản hồi bằng một chuỗi đơn giản như User not found có thể truy cập thông qua tham số data.

Tôi đang gặp khó khăn trong việc tìm ra cách thực hiện điều gì đó tương tự trong Alamofire. Dưới đây là những gì tôi có ngay bây giờ:

@IBAction func LoginPressed(sender: AnyObject) { 
    let params: Dictionary<String,AnyObject> = ["email": emailField.text, "password": passwordField.text] 

    Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params) 
     .responseJSON {(request, response, data, error) in 
      if error == nil { 
       dispatch_async(dispatch_get_main_queue(), { 
        let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController; 

        self.presentViewController(welcome, animated: true, completion: nil); 
       }) 
      } 
      else{ 
       dispatch_async(dispatch_get_main_queue(), { 
        // I want to set the error label to the simple message which I know the server will return 
        self.errorLabel.text = "something went wrong" 
       }); 
      } 
    } 
} 

Tôi không biết liệu tôi có xử lý đúng trường hợp không đúng hay không và cũng sẽ đánh giá cao đầu vào trên đó.

Trả lời

26

Bạn đang đang đi đúng hướng, nhưng bạn sẽ chạy vào một số vấn đề quan trọng với việc triển khai hiện tại của bạn. Có một số thứ cấp thấp của Alamofire sẽ giúp bạn đi lên mà tôi muốn giúp bạn. Đây là một phiên bản thay thế của mẫu mã của bạn sẽ có hiệu quả hơn nhiều.

@IBAction func loginPressed(sender: AnyObject) { 
    let params: [String: AnyObject] = ["email": emailField.text, "password": passwordField.text] 

    let request = Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params) 
    request.validate() 
    request.response { [weak self] request, response, data, error in 
     if let strongSelf = self { 
      let data = data as? NSData 

      if data == nil { 
       println("Why didn't I get any data back?") 
       strongSelf.errorLabel.text = "something went wrong" 
       return 
      } else if let error = error { 
       let resultText = NSString(data: data!, encoding: NSUTF8StringEncoding) 
       println(resultText) 
       strongSelf.errorLabel.text = "something went wrong" 
       return 
      } 

      var serializationError: NSError? 

      if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) { 
       println("JSON: \(json)") 
       let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController 
       self.presentViewController(welcome, animated: true, completion: nil) 
      } else { 
       println("Failed to serialize json: \(serializationError)") 
      } 
     } 
    } 
} 

Validation

Trước hết, các validate chức năng theo yêu cầu sẽ xác nhận như sau:

  • HTTPStatusCode - Chắc chắn là 200 ... 299
  • Content-Type - Đây tiêu đề trong phản hồi phải khớp với tiêu đề Accept trong yêu cầu ban đầu

Bạn có thể tìm thêm thông tin về xác thực trong Alamofire trong README.

Weakify/Strongify

Hãy chắc chắn để tự yếu và tự đóng cửa mạnh mẽ của bạn để chắc chắn rằng bạn không kết thúc việc tạo một giữ lại chu kỳ.

Dispatch để Queue chính

công văn của bạn gọi lại vào hàng đợi chính là không cần thiết. Alamofire đảm bảo rằng trình xử lý hoàn thành của bạn trong bộ nối tiếp responseresponseJSON được gọi trên hàng đợi chính. Bạn thực sự có thể cung cấp hàng đợi công văn của riêng bạn để chạy serializers nếu bạn muốn, nhưng không phải giải pháp của bạn hoặc của tôi hiện đang làm như vậy làm cho các cuộc gọi gửi đến hàng đợi chính hoàn toàn không cần thiết.

đáp ứng Serializer

Trong trường hợp cụ thể của bạn, bạn không thực sự muốn sử dụng responseJSON serializer. Nếu bạn làm như vậy, bạn sẽ không kết thúc nhận lại bất kỳ dữ liệu nào nếu bạn không vượt qua xác thực. Lý do là phản hồi từ việc tuần tự hóa JSON là những gì sẽ được trả về là AnyObject. Nếu tuần tự hóa không thành công, AnyObject sẽ không có và bạn sẽ không thể đọc dữ liệu.

Thay vào đó, hãy sử dụng trình nối tiếp response và cố gắng phân tích cú pháp dữ liệu theo cách thủ công với NSJSONSerialization. Nếu điều đó không thành công, thì bạn có thể dựa vào phương thức tốt 23 NSString(data:encoding:) để in ra dữ liệu.

Hy vọng điều này sẽ giúp làm sáng tỏ một số cách khá phức tạp để bị vấp ngã.

+0

Có sử dụng [tự yếu] cần thiết khi không được tham chiếu không? Tôi đã luôn luôn hiểu nó là nó không cần thiết nếu đóng cửa không được tham chiếu mạnh mẽ ở bất cứ đâu. – chourobin

+4

Câu hỏi hay, không thể đưa ra câu trả lời ngắn gọn. Nó phụ thuộc vào hành vi mà bạn muốn. Nếu bạn muốn chủ sở hữu của phương thức 'loginPressed' được giữ trong bộ nhớ bất kể nếu không có gì khác đang giữ một tham chiếu đến nó, thì bạn sẽ không muốn sử dụng' [weak self] '. Tuy nhiên, bạn luôn luôn có nguy cơ tiềm ẩn khi tạo chu kỳ giữ lại nếu bạn không sử dụng mẫu làm suy yếu/tăng cường. Thông tin thêm [tại đây] (http://blackpixel.com/blog/2014/03/capturing-myself.html) và [tại đây] (http://stackoverflow.com/questions/24320347/shall-we-always-use -unowned-self-inside-closure-in-swift). – cnoon

+0

Giải thích tốt. Trong Swift 3 bạn có thể thay thế 'if let strongSelf = self {...}' chỉ với 'guard let strongSelf = self else {return}' – Lion

1

Vì vậy, Alamofire xử lý tất cả các yêu cầu thành công. Điều này thực sự đi xuống đến tiêu đề http máy chủ API được trả lại.

Bạn có thể sử dụng Alamofire.Request.validate()

Nó sẽ cho phép bạn để xác nhận tiêu đề http, vv Kiểm tra ví dụ

https://github.com/Alamofire/Alamofire#validation

Tôi giả định được thông báo lỗi sẽ nằm trong đối tượng data.

để truy cập các giá trị từ dữ liệu bạn có thể làm một cái gì đó giống như

Tôi không thực sự chắc chắn về ngoại hình đáp ứng api của bạn, nhưng trong ví dụ này

{ 
    "message": "Could not authenticate" 
} 
let message: String? = data?.valueForKey("message") as String 
+0

Phải, mọi thứ được coi là thành công. Trong trường hợp lỗi, mã trạng thái có thể là 500 và tôi cho rằng '' 'error''' sẽ không rỗng. Trong trường hợp đó, '' 'data''' là' '' AnyObject''' và tôi không biết cách truy cập nội dung '' 'User not found''' thực tế. –