ios JSON解析错误Error Domain = NSCocoaErrorDomain Code=3840 上传文件并期待响应

Posted

技术标签:

【中文标题】ios JSON解析错误Error Domain = NSCocoaErrorDomain Code=3840 上传文件并期待响应【英文标题】:ios JSON parsing error Error Domain = NSCocoaErrorDomain Code=3840 when uploading file and expecting response 【发布时间】:2014-11-29 21:24:36 【问题描述】:

更新见文末

我正在构建我的第一个 ios 应用程序,并且我创建了许多功能,应用程序连接到服务器并获取数据。在应用程序仅发送数据的函数中,如果一切正常,我将服务器设置为使用以下 JSON 响应进行回复:

$reply = array('thisReply'=>'SUCCESS');
echo CJSON::encode($reply);

我在我的应用程序的其他功能中尝试了这个,这些功能将数据发送到服务器,它就像一个魅力。这是我用来发出请求的代码:

(stringUrl 只是我的服务器字符串)

    NSURL *url = [[NSURL alloc] initWithString:stringUrl];
    NSString *postMessage = [[NSString alloc] initWithFormat:@"username=%@&password=%@&requestedDataEntry=%@", currentUser.username, password, requestedData];
    //turn post string into data object
    NSData *postData = [requestPostMessage dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    //post data legnth
    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
    //url request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];

    //set up request properties
    [request setURL:requestURL];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:postData];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];


     //error attribute
    NSError *error = [[NSError alloc] init];

    //create response
    NSURLResponse *response;

    //json data
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

    //pass symptom history objects into an array
    NSDictionary *jsonReponseData = (NSDictionary *) [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];

我得到了正确的回复(键/值对 'thisReply'=>'SUCCESS')

这是我上传文件(并发送我的帖子数据)的功能,我从 *** 上的回复中复制了该文件:

  NSURL *url = [[NSURL alloc] initWithString:stringUrl];

//get curent user username and password
User *currentUser = [[User alloc]initWithSavedUser];
NSString *password = passWordString; //(not actual code)

//get also send as sms string
NSString *sendSMS = [[NSString alloc] init];
if(smsBoolean)

    sendSMS = @"YES";

else

    sendSMS = @"NO";

//get file attached string
NSString *recordedMessageExists = [[NSString alloc] init];
if(recordedMessageBoolean)

    recordedMessageExists = @"YES";

else

    recordedMessageExists = @"NO";


NSDictionary *params = @@"username" : currentUser.username,
                         @"password" : password,
                         @"patientID" : patientID,
                         @"sendSMS" : sendSMS,
                         @"message" : message,
                         @"attachFile" : recordedMessageExists;

//get an array with the files path
NSArray *pathsArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//copy documents path into an nstring
NSString *documentsPath = [pathsArray objectAtIndex:0];
//get path for recorded message
NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:fileNameString];

//create request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];

NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];

NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

//set request http method and url
[request setHTTPMethod:@"POST"];
[request setURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];

// Append parameters data into post url
NSMutableData *body = [NSMutableData data];

[params enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) 
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
];

// attach file if user has added one
if(recordedMessageBoolean)

    //get filename
    NSString *filename  = [soundFilePath lastPathComponent];
    NSData   *data      = [NSData dataWithContentsOfFile:soundFilePath];
    NSString *mimetype  = [self mimeTypeForPath:soundFilePath];
    //append file to post body
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", @"messageFile", filename] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:data];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

//set request's body
[request setHTTPBody:body];
//post data legnth
NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
// create url response
NSURLResponse *response;
//set up NSerror
NSError *error = [[NSError alloc] init];

//-- Getting response form server
//send update to server
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

//pass reply into an NSDictionary
NSDictionary *jsonReponseData = (NSDictionary *) [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];

还有 mimeTypeForPath 函数

- (NSString *)mimeTypeForPath:(NSString *)path

// get a mime type for an extension using MobileCoreServices.framework

CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);


NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));


CFRelease(UTI);

return mimetype;

帖子数据连同声音文件被正确发送到服务器,服务器执行其所有功能,但是当它返回 json 回复时,已设置 responseData,但 NSDictionary jsonResponseData 为 nil,我收到错误报告说:

JSON parsing error Error Domain = NSCocoaErrorDomain Code=3840

NSDebugDescription @"JSON text did not begin with an array or object....".

我在网上搜索了这些错误,所有结果都说当 JSON 字符串有问题时会出现此错误,但是相同的 json 字符串在第一个函数中起作用,所以我认为这一定是我做错了有请求,但我从各地得到了所有代码,很难说出导致错误的原因。有人可以帮帮我吗?

更新

我记录了响应数据,结果发现整个网页都是 JSON 响应,这就是导致问题的原因。

更新 2 和最终答案

我发现了错误。我有代码将发送的文件临时复制到服务器,然后将其附加到电子邮件中并将其发送出去(最后删除了文件)。但是我在 if 检查之外有这个检查要附加的文件是否是甚至由应用程序发布。在我进行 if 检查后,此错误在任何一种情况下都停止发生(有或没有附加文件)。

【问题讨论】:

顺便说一句,当你遇到直接的问题时,我建议你删除sendSynchronousRequest 的代码。你永远不想从主队列发出同步请求。 完成后我会在谷歌上搜索相关教程,谢谢 另请注意,在您的原始x-www-form-urlencoded 请求中,您没有对参数进行百分比编码。例如,如果密码中包含&+,则此代码将不起作用。始终对您的 x-www-form-urlencoded 请求进行百分比编码(但不是您的 multipart/form-data 请求)。 【参考方案1】:

你应该检查responseData的内容,例如,

NSLog(@"responseData = %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);

我怀疑您会发现它不符合有效的 JSON。编辑您的问题,向我们展示它所说的内容。

您可能想要记录 response 对象并确保 statusCode 也是 200。如果不是 200,那么你有一些服务器相关的问题。

顺便说一句,您的 JSON 解析例程不使用 error 参数。每当您的代码出现问题时,请确保您使用了所有可用的错误日志记录。

【讨论】:

是的,你是对的.....我将整个网页作为 JSON 响应:S。我不知道为什么 它通常是一个 html 页面,报告由以下任一原因引起的错误: (a) 服务器 php 代码中的错误; (b) 服务器在请求中查找未正确提供的内容,但服务器代码没有妥善处理错误;或 (c) 请求中的一些简单错误(例如返回 HTML 页面的错误 URL,通知您 404 服务器代码)。这就是为什么我建议查看response 对象中的statusCode,因为这有时可以帮助您以编程方式诊断问题的根源。 我发现了错误。我有代码将发送的文件临时复制到服务器,然后将其附加到电子邮件中并将其发送出去(最后删除了文件)。但是我在 if 检查之外进行了此操作,以检查应用程序是否甚至发布了要附加的文件。在我进行 if 检查后,此错误在任何一种情况下都停止发生(有或没有附加文件)。非常感谢 Rob :)。

以上是关于ios JSON解析错误Error Domain = NSCocoaErrorDomain Code=3840 上传文件并期待响应的主要内容,如果未能解决你的问题,请参考以下文章

iOS解析数据时Error=3840

ios JSON解析常见错误

Error Domain = NSCocoaErrorDomain Code=3840 "操作无法完成。(Cocoa 错误 3840。)

错误:无法解析来自 id 的引用 error.json #

解析错误处理 swift 3

未解决的错误 Error Domain=NSCocoaErrorDomain Code=132001 "(null)"