iOS应用HTTP错误处理最佳实践及登录请求场景问题咨询
Hey there! Let's walk through the best practices for handling errors in your iOS network module—specifically for login requests using NSURLRequest and NSURLSessionDelegate. I’ve dealt with this exact scenario plenty of times, so here’s what works well:
1. Split Errors Into Two Core Categories
The first step is to separate the two main types of errors you’ll encounter: system-level NSError instances, and HTTP status code-based errors (even when no NSError is returned).
System/Network Errors (NSError)
These are errors thrown by the system or network stack—things like no internet, timeouts, or canceled requests. You’ll catch these in the URLSession:task:didCompleteWithError: delegate method.
Here’s how to handle them with clear, user-friendly logic:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { NSInteger errorCode = error.code; NSString *userFriendlyMessage; switch (errorCode) { case NSURLErrorNotConnectedToInternet: userFriendlyMessage = @"Please check your internet connection"; break; case NSURLErrorCancelled: // Skip user feedback if the user initiated the cancel userFriendlyMessage = nil; break; case NSURLErrorTimedOut: userFriendlyMessage = @"Request timed out—please try again later"; break; default: userFriendlyMessage = @"Network request failed. Please try again."; break; } // Show the message to the user (use UIAlertController or your custom toast) if (userFriendlyMessage) { [self showUserAlertWithMessage:userFriendlyMessage]; } // Report the full error to your monitoring platform for debugging [self logErrorToMonitoring:error task:task]; return; } // No system error? Now handle HTTP status codes NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response; [self handleHTTPResponse:httpResponse task:task]; }
HTTP Status Code Errors
Even when no NSError is returned, non-2xx status codes mean something went wrong. You’ll need to parse the response and handle these based on their ranges:
- (void)handleHTTPResponse:(NSHTTPURLResponse *)response task:(NSURLSessionTask *)task { NSInteger statusCode = response.statusCode; if (statusCode >= 200 && statusCode < 300) { // Success! Parse the login response (e.g., extract auth token) NSError *parseError; NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:task.responseData options:0 error:&parseError]; if (parseError) { [self handleParseError:parseError]; return; } // Proceed with login success logic NSString *authToken = responseJSON[@"auth_token"]; [self saveAuthToken:authToken]; [self navigateToHomeScreen]; } else if (statusCode >= 400 && statusCode < 500) { // Client-side errors NSString *userMessage; switch (statusCode) { case 401: // Unauthorized: Wrong credentials or expired token userMessage = @"Incorrect username or password. Please try again."; // If this is an expired token, redirect to login screen [self resetLoginStateAndShowLoginScreen]; break; case 400: userMessage = @"Invalid request. Please check your input."; break; case 404: userMessage = @"Requested resource not found."; // Log this for backend debugging—likely a misconfigured endpoint [self logStatusCodeError:statusCode task:task]; break; default: userMessage = @"Request failed. Please try again."; break; } [self showUserAlertWithMessage:userMessage]; } else if (statusCode >= 500 && statusCode < 600) { // Server-side errors (500, 502, 503, etc.) NSString *userMessage = @"Server is busy. Please try again later."; [self showUserAlertWithMessage:userMessage]; // Log these immediately—backend team needs to investigate [self logStatusCodeError:statusCode task:task]; } else { // Unhandled status codes (e.g., 3xx redirects—NSURLSession usually handles these automatically) NSLog(@"Unhandled HTTP status code: %ld", (long)statusCode); [self logStatusCodeError:statusCode task:task]; } }
2. Key Best Practices to Standardize Your Error Handling
- Encapsulate Reusable Logic: Create a dedicated
NetworkErrorHandlerclass or a baseNSURLSessionDelegatesubclass to avoid duplicating error code across every request. - Prioritize User Experience: Never show raw error codes or technical messages to users. Always translate errors into simple, actionable language.
- Implement Retry Logic: For transient errors (timeouts, 5xx codes), add a limited retry mechanism (2-3 attempts max) to improve success rates without spamming servers.
- Comprehensive Error Logging: For every error, log details like the request URL, parameters, timestamp, device info, and full error message. This is critical for debugging production issues.
- Distinguish Business vs. System Errors: A 401 (wrong password) is a business error that needs user input, while a network timeout is a system error that just needs a retry prompt. Handle them differently.
内容的提问来源于stack exchange,提问作者Alexis Darnat

