HTTP POST传多类型参数触发NSInvalidArgumentException问题求助
Hey there, let's break down why you're running into that NSInvalidArgumentException and fix it step by step:
1. 核心触发原因:JSON无法序列化Data类型
Look at your postString dictionary—you're trying to put requestData (a Data object) into it with the key "receiptData".
JSON serialization only supports JSON-compatible types: strings, numbers, arrays, dictionaries, booleans, and null. Binary Data isn't part of the JSON spec, so when JSONSerialization.data(withJSONObject:) tries to process this dictionary, it hits a non-serializable type and throws the exception you're seeing.
2. 额外的请求逻辑问题
You're using uploadTask(with: request, from: requestData) but also setting request.httpBody to the serialized postString data. This creates a conflict: the from parameter in uploadTask will overwrite your pre-set httpBody, so your full parameter set won't be sent to the server. You should use a regular dataTask instead since you're already assembling the full request body.
修正后的代码片段
Here's how to adjust your code to fix both issues:
func receiptValidation() { let SUBSCRIPTION_SECRET = mySecretKey let defaults = UserDefaults.standard guard let receiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: receiptURL.path) else { print("Receipt file not found") return } do { let receiptData = try Data(contentsOf: receiptURL, options: .alwaysMapped) let base64encodedReceipt = receiptData.base64EncodedString(options: .endLineWithCarriageReturn) // 直接使用Base64编码后的字符串,而非Data类型 let postString: [String: Any] = [ "receiptData": base64encodedReceipt, "deviceType": "IOS", // 用可选绑定避免强制解包崩溃 "subscriberId": encodeString(normalString: (defaults.array(forKey: "userDetails")?.first as? String) ?? ""), "password": encodeString(normalString: (defaults.array(forKey: "userDetails")?.last as? String) ?? ""), "productId": PurchaseManager.instance.productId, "code": opcodeDetails["opCode"] ?? "" ] guard JSONSerialization.isValidJSONObject(postString) else { print("postString is not valid JSON") return } let requestData = try JSONSerialization.data(withJSONObject: postString) guard let apiBaseUrl = opcodeDetails["apiProxyBaseUrl"], let url = URL(string: "\(apiBaseUrl)/api/validate-receipt-data") else { print("Invalid API URL") return } var request = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = requestData // 使用dataTask而非uploadTask,因为已设置完整的httpBody let task = session1?.dataTask(with: request) { (data, response, error) in if let error = error { print("Request error: \(error.localizedDescription)") return } guard let data = data else { print("No data received") return } do { let appReceiptJSON = try JSONSerialization.jsonObject(with: data) print("Success! Receipt response: \(appReceiptJSON)") } catch { print("JSON parsing failed: \(error.localizedDescription)") } } task?.resume() } catch { print("Error processing receipt: \(error.localizedDescription)") } }
额外建议
- Avoid force unwraps (
!): They're a common source of crashes. Use optional bindings (if let,guard let) or default values like?? ""to handle nil cases gracefully. - Validate all inputs: Double-check that values like
opcodeDetails["opCode"]anduserDetailsexist and are of the correct type before using them. - Check JSON validity: Always use
JSONSerialization.isValidJSONObject(_:)before attempting to serialize a dictionary to catch issues early.
内容的提问来源于stack exchange,提问作者Priya Sri

