Alamofire 中的错误处理

Error handling in Alamofire

我在 AngularJS 控制器中有 HTTP 代码:

$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 = "";
    });

在成功的情况下,服务器将响应一个 JSON 用户表示。在错误情况下,服务器将使用一个简单的字符串作为响应,例如 User not found,可以通过 data 参数访问该字符串。

我不知道如何在 Alamofire 中做类似的事情。这是我现在拥有的:

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

我也不知道我是否正确处理了非错误情况,也希望对此提出意见。

所以 Alamofire 将所有请求都视为成功。这实际上归结为 API 服务器 http headers 被返回。

你可以使用 Alamofire.Request.validate()

它将允许您验证 http headers 等。查看示例

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

我假设错误消息将在 data object.

要访问数据中的值,您可以执行类似

的操作

我不太确定你的 api 回复看起来如何,但在这个例子中

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

您走在正确的轨道上,但是您将 运行 解决当前实施的一些关键问题。有一些低级别的 Alamofire 东西会让你绊倒,我想帮助你。这是您的代码示例的另一个版本,它会更有效。

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

验证

首先,请求中的 validate 函数将验证以下内容:

  • HTTPStatusCode - 必须为 200...299
  • Content-Type - 响应中的这个 header 必须匹配原始请求中的 Accept header

您可以在 README.

中找到有关 Alamofire 验证的更多信息

弱化/强化

确保你的闭包弱化自我并强化自我,以确保你最终不会创建一个保留周期。

调度到主Queue

您的调度调用回主 queue 是没有必要的。 Alamofire 保证 responseresponseJSON 序列化程序中的完成处理程序已经在主 queue 上调用。如果你愿意,你实际上可以提供你自己的调度 queue 到 运行 序列化器,但是你的解决方案或我的解决方案目前都没有这样做,使得对主 queue 的调度调用完全没有必要。

响应序列化器

在您的特定情况下,您实际上并不想使用 responseJSON 序列化程序。如果这样做,如果您没有通过验证,您将不会最终获得任何数据。原因是来自 JSON 序列化的响应将作为 AnyObject 返回。如果序列化失败,AnyObject 将为 nil,您将无法读取数据。

相反,使用 response 序列化程序并尝试使用 NSJSONSerialization 手动解析数据。如果失败,那么您可以依靠好的 ole NSString(data:encoding:) 方法来打印数据。

希望这有助于阐明一些相当复杂的被绊倒的方法。