2013-10-29 32 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請求的良好開端。