使用URLSession发送POST请求:动态参数构建失败排查
Hey there! I see exactly what's going wrong here—your dynamic parameter string isn't properly URL-encoded, which is causing the server to throw that semantic error. Let's break this down and fix it step by step.
The Root Cause
When you use string interpolation like "\(username)", any special characters in your input (like @, &, spaces, or =) won't be encoded to fit the application/x-www-form-urlencoded format. Your static string works because you're using a valid, pre-encoded example, but dynamic values need proper encoding to avoid breaking the request structure.
Solution 1: Use URLComponents (Recommended)
URLComponents automatically handles URL encoding for query items, so this is the safest approach. Here's how to adjust your code:
if let url = URL(string: Constants.REGISTRATION_URL){ var request = URLRequest(url: url) request.httpMethod = "POST" // Set the correct Content-Type (lowercase 'application' per HTTP specs) request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") // Build query items with your dynamic values var urlComponents = URLComponents() urlComponents.queryItems = [ URLQueryItem(name: "name", value: username), URLQueryItem(name: "password", value: password), URLQueryItem(name: "email", value: email), URLQueryItem(name: "c_password", value: confirmPassword) ] // Extract the encoded query string and set it as the request body if let encodedQuery = urlComponents.percentEncodedQuery { request.httpBody = encodedQuery.data(using: .utf8) } else { // Handle error if encoding fails (e.g., invalid input) self.showAlertMessage(alertMessage: "Invalid input parameters") return } APIManager.sharedInstance.postCall(request: request, onSuccess: { json in DispatchQueue.main.async { // Handle your success logic here } }, onFailure: { error in do{ let errorModel = try JSONDecoder().decode(ErrorModel.self, from: Data(error.utf8)) DispatchQueue.main.async { self.showAlertMessage(alertMessage: errorModel.errors[0].detail) } }catch{ DispatchQueue.main.async { self.showAlertMessage(alertMessage: error.localizedDescription) } } }) }
Solution 2: Manually Encode a Dictionary
If you prefer working with a dictionary, you can create a helper function to encode each key-value pair properly:
// Helper function to encode dictionary to x-www-form-urlencoded string func encodeParameters(_ parameters: [String: String]) -> String? { return parameters.compactMap { key, value in guard let encodedKey = key.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let encodedValue = value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return nil } return "\(encodedKey)=\(encodedValue)" }.joined(separator: "&") } // Usage in your request: if let url = URL(string: Constants.REGISTRATION_URL){ var request = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") let params: [String: String] = [ "name": username, "password": password, "email": email, "c_password": confirmPassword ] guard let encodedParams = encodeParameters(params) else { self.showAlertMessage(alertMessage: "Invalid input parameters") return } request.httpBody = encodedParams.data(using: .utf8) // Rest of your postCall code remains the same... }
Key Notes
- Always use proper URL encoding for
application/x-www-form-urlencodedrequests—never rely on raw string interpolation. - Make sure your
Content-Typeheader uses lowercaseapplication(this is the HTTP standard, though some servers may tolerate uppercase, but it's best to follow specs).
内容的提问来源于stack exchange,提问作者Rigsby

