我正在编写一个需要与后端服务器通信的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调用,这就是上面代码返回的内容。
为什么会这样?这是第一次来自服务器的响应吗?
答案 0 :(得分:1)
在研究Web服务的登录API时,会发现一些不相关的观察结果:
如果从主队列执行此操作,则应该异步发送此信息。切勿从主队列发出同步网络请求。如果您在主队列(a)上同步执行此操作,则可能会让iOS监视程序进程终止您的应用程序,如果主队列在处理某些同步网络请求时无响应,则会发生这种情况; (b)在网络请求期间简单地冻结应用程序是一个糟糕的用户体验...如果需要,请在网络请求正在进行时禁用UI并显示不确定的进度指示器(UIActivityIndicatorView
)。 / p>
您应该为forHTTPHeaderField
设置值Content-Length
。这可能不是必需的,但这是一种很好的做法。
您可能不应该使用带有用户ID和密码的JSON字符串,而是应该使用NSJSONSerialization
之类的内容从NSDictionary
构建此字符串。实际上,如果您的密码有任何需要转义的字符(例如引号),则现有代码可能无效。使用NSJSONSerialization
是确保正确格式化JSON的简便方法。
您可能不应该在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的异步请求。