iOS:一个电话有两个请求?

标签 ios objective-c rest

我正在编写一个需要与后端服务器通信的 iPad 应用程序。使用这个后端的首要任务是登录,为此服务器有一个我们可以 POST 到的 URL,我这样做是这样的:

    // Create the request.
NSString* loginURL = @"http://foo.local/signature/service/auth/rest/firewall/login";
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:loginURL]];

NSString* credentials = @"{\"userName\":\"foo2@foolinator.com\", \"password\":\"password\"}";

[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:[credentials dataUsingEncoding:NSASCIIStringEncoding
                               allowLossyConversion:YES]];

// Logging in...
NSError* error = nil;
NSURLResponse* response;
NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
NSString* responseString = [NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]];

NSLog(@"Response String is: %@\n", responseString);
NSLog(@"Header fields are: %@\n", [httpResponse allHeaderFields]);

奇怪的是,我得到的响应是错误 405:方法不允许。如果我正在执行 GET,我会预料到这一点,但我正在执行 POST。

我安装了 WireShark 来检查 HTTP 请求,看起来实际上有两个请求。第一个是 POST 调用,服务器返回一些 cookie 信息作为响应,然后是第二个 GET 调用,这就是上面的代码返回的内容。

为什么会这样?跟服务器第一次响应有关系吗?

最佳答案

当您研究 Web 服务的登录 API 时,出现了一些不相关的观察结果:

  1. 如果从主队列执行此操作,您应该异步发送此消息。切勿从主队列发出同步网络请求。如果您在主队列上同步执行此操作 (a),您可能会面临 iOS 看门狗进程杀死您的应用程序的风险,如果在处理某些同步网络请求时主队列变得无响应,就会发生这种情况; (b) 在网络请求期间简单地卡住应用程序是一个糟糕的用户体验...如果需要,请在网络请求正在进行时禁用 UI 并显示不确定的进度指示器 (a UIActivityIndicatorView )。

  2. 您可能应该设置一个值 forHTTPHeaderField对于 Content-Length 。这可能不是必需的,但这是一个很好的做法。

  3. 您可能不应该使用包含用户 ID 和密码的 JSON 字符串,而应该使用类似 NSJSONSerialization 的内容从 NSDictionary 构建此字符串。 。事实上,例如,如果您的密码包含任何需要转义的字符(例如引号),则现有代码可能无法工作。使用 NSJSONSerialization 是确保 JSON 格式正确的简单方法。

  4. 您可能不应该在 JSON 请求中以明文形式发送密码。至少,我希望你的服务器采用HTTPS。

无论如何,根据这些观察,假设您的服务器确实正在等待 JSON 请求,我可能会建议如下:

// hopefully your production server is employing HTTPS

NSString *loginURL = @"https://foo.local/signature/service/auth/rest/firewall/login";

// use NSJSONSerialization to create JSON rather than building it in a NSString

NSDictionary *postDictionary = @{@"userName": userName, @"password": password}; // assuming you have NSString variables, `userName` and `password`
NSError *error = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:postDictionary options:0 error:&error];
NSAssert(postData, @"dataWithJSONObject failed: %@", error);

// when creating request, also set Content-Length

NSURL *url = [NSURL URLWithString:loginURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:postData];
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];

// issue request asynchronously

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    if (connectionError) {
        NSLog(@"sendAsynchronousRequest error: %@", connectionError);
        return;
    }

    // process the server response here
}];

您可能仍想使用NSURLConnectionDataDelegate/NSURLConnectionDelegate基于请求(您可以识别重定向、质询、根据需要取消请求等),但上述内容可能是基于异步 JSON 请求的良好开端。

关于iOS:一个电话有两个请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19666500/

相关文章:

objective-c - 圆弧和 Malloc : EXEC_BAD_ACCESS

rest - 将定制的聊天机器人与 Skype 集成

python - django-rest-框架 : list parameters in URL

IOS/objective-C/ Storyboard : Detect when show segue underway

iOS:在通话/录音/热点 session 期间,启动图像在中心起皱

java - 如果请求参数超过 15 个,POST 或 GET 应该使用什么?

ios - 检测已取消的 iTunes 登录警报以进行应用内购买

ios - "ionic run ios"如何添加配置文件

ios - 保存数据以便稍后显示

ios - 在所有请求完成后执行代码(Facebook SDK)