Swift POST请求报错:Invalid type in JSON write问题求助
Swift调用机器学习API报错排查(Postman正常,Xcode崩溃)
问题场景
调用https://doctagon.herokuapp.com/diagnose的POST接口时,Postman发送请求可正常返回结果,但Swift实现的代码触发崩溃,错误提示为Invalid type in JSON write (Foundation.__NSSwiftData)。
原请求代码
func makePOSTRequest() { print("entered request function") guard let url = URL(string: "https://doctagon.herokuapp.com/diagnose") else { print("error with getting the URL") return } print("got the URL") var request = URLRequest(url: url) print("Got the request") // method, body, headers? request.httpMethod = "POST" print("got the http.method = 'POST'") // might not need this --> request.setValue(" symptoms", forHTTPHeaderField: "Content-Type") let body: [String: AnyHashable] = [ "symptoms": ["Headache", "Sweating"] ] print("got the body") print("About to enter the .httpBody part of the code") request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed) //Make the request let task = URLSession.shared.dataTask(with: request) { data, _, error in guard let data = data, error == nil else { print("error with making sure that there is data") return } print("got data") do { let response = try JSONSerialization.data(withJSONObject: data, options: .fragmentsAllowed) print("SUCCESS \(response)") } catch { print("error with the conversion of the JSOn") print(error) } } task.resume() print("resumed Task") }
错误日志
2022-11-19 23:39:30.335160-0500 Doctagon[88188:1838200] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Foundation.__NSSwiftData)' *** First throw call stack: ( 0 CoreFoundation 0x000000018040e7ec __exceptionPreprocess + 172 1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56 2 Foundation 0x0000000180c446f8 _writeJSONValue + 704 3 Foundation 0x0000000180c443f8 -[_NSJSONWriter dataWithRootObject:options:] + 84 4 Foundation 0x0000000180c470d0 +[NSJSONSerialization dataWithJSONObject:options:error:] + 108 5 Doctagon 0x0000000100be4080 $s8Doctagon12QuestionViewV15makePOSTRequestyyFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtYbcfU_ + 544 6 Doctagon 0x0000000100be45ec $s10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIeghggg_So6NSDataCSgAGSo7NSErrorCSgIeyBhyyy_TR + 264 7 CFNetwork 0x0000000183df9928 CFNetwork + 31016 8 CFNetwork 0x0000000183e14a4c _CFHTTPMessageSetResponseProxyURL + 14648 9 libdispatch.dylib 0x0000000104c30594 _dispatch_call_block_and_release + 24 10 libdispatch.dylib 0x0000000104c31d5c _dispatch_client_callout + 16 11 libdispatch.dylib 0x0000000104c3a040 _dispatch_lane_serial_drain + 928 12 libdispatch.dylib 0x0000000104c3adb8 _dispatch_lane_invoke + 484 13 libdispatch.dylib 0x0000000104c48b40 _dispatch_workloop_worker_thread + 1720 14 libsystem_pthread.dylib 0x00000001af2568fc _pthread_wqthread + 284 15 libsystem_pthread.dylib 0x00000001af2556c0 start_wqthread + 8 ) libc++abi: terminating with uncaught exception of type NSException *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Foundation.__NSSwiftData)' terminating with uncaught exception of type NSException CoreSimulator 857.13 - Device: iPhone 14 Pro (4108291D-D836-4715-8386-5237B6D217E7) - Runtime: iOS 16.1 (20B72) - DeviceType: iPhone 14 Pro
错误原因
- 核心错误:处理API返回数据时,错误调用了
JSONSerialization.data(withJSONObject: data, ...)——该方法的作用是将JSON对象(字典/数组)转成二进制数据,但你传入的data本身就是API返回的二进制数据,类型不匹配直接触发崩溃。正确做法是用JSONSerialization.jsonObject(with: data, ...)把二进制数据解析成JSON对象。 - 次要问题:请求未设置
Content-Type: application/json头,Postman会自动添加该头,但Swift中如果不设置,服务器可能无法正确解析请求体;另外try?处理请求体序列化会默默失败,无法排查序列化错误。
修正后的代码
func makePOSTRequest() { print("entered request function") guard let url = URL(string: "https://doctagon.herokuapp.com/diagnose") else { print("error with getting the URL") return } print("got the URL") var request = URLRequest(url: url) request.httpMethod = "POST" // 必须设置Content-Type,告诉服务器请求体是JSON格式 request.setValue("application/json", forHTTPHeaderField: "Content-Type") let body: [String: Any] = [ "symptoms": ["Headache", "Sweating"] ] do { // 用do-catch处理序列化错误,避免默默失败 request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) } catch { print("Failed to serialize request body: \(error)") return } let task = URLSession.shared.dataTask(with: request) { data, _, error in guard let data = data, error == nil else { print("Request error: \(error ?? NSError(domain: "UnknownError", code: -1, userInfo: nil))") return } print("got data") do { // 正确解析返回的JSON数据为对象(字典/数组) let responseObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) print("SUCCESS: \(responseObject)") // 可选:转成字符串查看原始返回内容 if let jsonString = String(data: data, encoding: .utf8) { print("JSON String: \(jsonString)") } } catch { print("Failed to parse response JSON: \(error)") // 排查用:查看原始返回的字符串形式 if let rawString = String(data: data, encoding: .utf8) { print("Raw response: \(rawString)") } } } task.resume() print("resumed Task") }
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

