2013-10-29 31 views
0

我正在编写需要与后端服务器通信的iPad应用程序。企业在使用这个后端的第一步是登录,并为这个服务器有一个我们可以张贴到一个URL,我这样做:iOS:来自一个呼叫的两个请求?

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

NSString* credentials = @"{\"userName\":\"[email protected]\", \"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调用,这是上面的代码返回的。

为什么会发生这种情况?第一次与服务器的响应有关吗?

+1

您是否正在重定向? – Wain

+0

是的,这绝对是一种可能性,IP地址是不同的。我应该如何处理? – easythrees

+0

你怎么没有使用AFNetworking或其他网络库? –

回答

1

当你研究你的Web服务的API登录,几个不相关的意见:

  1. 如果从主队列这样做,你应该异步发送此。切勿从主队列发出同步网络请求。如果您在主队列(a)上同步执行此操作,则可能会导致iOS看门狗进程终止您的应用程序,如果主队列在某些同步网络请求正在处理时变得无响应,则会发生这种情况。 (b)在网络请求期间简单地冻结应用程序是个不好的UX ...如果需要,请禁用UI并在网络请求正在进行时显示不确定的进度指示器(UIActivityIndicatorView)。

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

  3. 您可能不应该使用带有用户名和密码的JSON字符串,而应该使用类似NSJSONSerializationNSDictionary来构建此字符串。事实上,如果您的密码中有任何需要转义的字符(例如引号),则现有的代码可能无法使用。使用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请求的良好开端。