ios Alamofire 中的错误处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29024703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 05:11:26  来源:igfitidea点击:

Error handling in Alamofire

iosangularjsswiftalamofire

提问by Paymahn Moghadasian

I have the HTTP code in an AngularJS controller:

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

In the success case, the server will respond with a JSON representation of a user. In the error case the server will respond with a simple string such as User not foundwhich can be accessed through the dataparameter.

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

I'm having trouble figuring out how to do something similar in Alamofire. Here's what I have right now:

我无法弄清楚如何在 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"
                });
            }
    }
}

I have no idea if I'm handling the non-error case correctly either and would appreciate input on that as well.

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

回答by cnoon

You are are on the right track, but you are going to run into some crucial issues with your current implementation. There are some low level Alamofire things that are going to trip you up that I want to help you out with. Here's an alternative version of your code sample that will be much more effective.

您走在正确的轨道上,但是您将遇到当前实施的一些关键问题。有一些低级的 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)")
            }
        }
    }
}

Validation

验证

First off, the validatefunction on the request will validate the following:

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

  • HTTPStatusCode- Has to be 200...299
  • Content-Type- This header in the response must match the Acceptheader in the original request
  • HTTPStatusCode- 必须是 200...299
  • Content-Type- 响应中的此标头必须与Accept原始请求中的标头匹配

You can find more information about the validation in Alamofire in the README.

您可以在自述文件中找到有关 Alamofire 中验证的更多信息。

Weakify / Strongify

削弱/加强

Make sure to weak self and strong self your closure to make sure you don't end up creating a retain cycle.

确保弱自我和强自我你的闭包,以确保你最终不会创建一个保留循环。

Dispatch to Main Queue

调度到主队列

Your dispatch calls back to the main queue are not necessary. Alamofire guarantees that your completion handler in the responseand responseJSONserializers is called on the main queue already. You can actually provide your own dispatch queue to run the serializers on if you wish, but neither your solution or mine are currently doing so making the dispatch calls to the main queue completely unnecessary.

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

Response Serializer

响应序列化器

In your particular case, you don't actually want to use the responseJSONserializer. If you do, you won't end up getting any data back if you don't pass validation. The reason is that the response from the JSON serialization is what will be returned as the AnyObject. If serialization fails, the AnyObjectwill be nil and you won't be able to read out the data.

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

Instead, use the responseserializer and try to parse the data manually with NSJSONSerialization. If that fails, then you can rely on the good ole NSString(data:encoding:)method to print out the data.

相反,使用response序列化程序并尝试使用NSJSONSerialization. 如果失败,那么您可以依靠好的 oleNSString(data:encoding:)方法打印出数据。

Hopefully this helps shed some light on some fairly complicated ways to get tripped up.

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

回答by slik

So Alamofire treats all requests successful. This really comes down to the API server http headers being returned.

所以 Alamofire 处理所有请求都成功。这实际上归结为返回的 API 服务器 http 标头。

You could use Alamofire.Request.validate()

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

It'll allow you to validate http headers, etc. Check out the example

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

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

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

I am assuming the the error message will be in the dataobject.

我假设错误消息将在data对象中。

to access the values from data you could do something like

要访问数据中的值,您可以执行以下操作

I am not really sure about your api response looks but in this example

我不太确定你的 api 响应看起来,但在这个例子中

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