iOS使用NSJSONSerialization发送POST请求中的JSON数据

3

我知道有类似的问题,因为我已经阅读了大部分,但仍然遇到了问题。我试图向服务器发送 JSON 数据,但我不认为 JSON 数据被接收到。我不确定我错过了什么。下面是我的代码...

发送数据到服务器的方法。

- (void)saveTrackToCloud
{
    NSData *jsonData = [self.track jsonTrackDataForUploadingToCloud];  // Method shown below.
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"%@", jsonString);  // To verify the jsonString.

    NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:http://www.myDomain.com/myscript.php] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];
    [postRequest setHTTPMethod:@"POST"];
    [postRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [postRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [postRequest setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"];
    [postRequest setHTTPBody:jsonData];

    NSURLResponse *response = nil;
    NSError *requestError = nil;
    NSData *returnData = [NSURLConnection sendSynchronousRequest:postRequest returningResponse:&response error:&requestError];

    if (requestError == nil) {
        NSString *returnString = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSUTF8StringEncoding];
        NSLog(@"returnString: %@", returnString);
    } else {
        NSLog(@"NSURLConnection sendSynchronousRequest error: %@", requestError);
    }
}

方法jsonTrackDataForUploadingToCloud

-(NSData *)jsonTrackDataForUploadingToCloud
{
    // NSDictionary for testing.
    NSDictionary *trackDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"firstValue", @"firstKey", @"secondValue", @"secondKey", @"thirdValue", @"thirdKey", nil];

    if ([NSJSONSerialization isValidJSONObject:trackDictionary]) {

        NSError *error;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:trackDictionary options:NSJSONWritingPrettyPrinted error:&error];

        if (error == nil && jsonData != nil) {
            return jsonData;
        } else {
            NSLog(@"Error creating JSON data: %@", error);
            return nil;
        }

    } else {

        NSLog(@"trackDictionary is not a valid JSON object.");
        return nil;
    }
}

这是我的PHP代码。

<?php
    var_dump($_POST);
    exit;
?>

我从 NSLog(@"returnString: %@", returnString); 接收到的输出是...
returnString: array(0) {
} 
2个回答

6

在你的PHP代码里,你使用了$_POST变量,它是用于处理application/x-www-form-urlencoded请求内容类型(或其他标准的HTTP请求)。但如果你需要获取JSON数据,你应该检索原始数据:

<?php

    // read the raw post data

    $handle = fopen("php://input", "rb");
    $raw_post_data = '';
    while (!feof($handle)) {
        $raw_post_data .= fread($handle, 8192);
    }
    fclose($handle); 

    echo $raw_post_data;
?>

然而更有可能的是,你想把那个 JSON $raw_post_data 解码成关联数组 ($request 是我的示例名称),然后根据请求构建一个关联数组 $response ,再将其编码为 JSON 并返回。我还将设置响应的 content-type 以明确它是 JSON 响应。请参考以下随机示例:

<?php

    // read the raw post data

    $handle = fopen("php://input", "rb");
    $raw_post_data = '';
    while (!feof($handle)) {
        $raw_post_data .= fread($handle, 8192);
    }
    fclose($handle);

    // decode the JSON into an associative array

    $request = json_decode($raw_post_data, true);

    // you can now access the associative array, $request

    if ($request['firstKey'] == 'firstValue') {
        $response['success'] = true;
    } else {
        $response['success'] = false;
    }

    // I don't know what else you might want to do with `$request`, so I'll just throw
    // the whole request as a value in my response with the key of `request`:

    $response['request'] = $request;

    $raw_response = json_encode($response);

    // specify headers

    header("Content-Type: application/json");
    header("Content-Length: " . strlen($raw_response));

    // output response

    echo $raw_response;
?>

这并不是一个特别有用的例子(只是检查与firstKey关联的值是否为'firstValue'),但希望它能说明解析请求和创建响应的思路。

另外还有一些小提示:

  1. You might want to include the checking of the status code of the response (since from NSURLConnection perspective, some random server error, like 404 - page not found) will not be interpreted as an error, so check the response codes.

    You'd obviously probably want to use NSJSONSerialization to parse the response:

    [NSURLConnection sendAsynchronousRequest:postRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if (error) {
            NSLog(@"NSURLConnection sendAsynchronousRequest error = %@", error);
            return;
        }
    
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
            if (statusCode != 200) {
                NSLog(@"Warning, status code of response was not 200, it was %d", statusCode);
            }
        }
    
        NSError *parseError;
        NSDictionary *returnDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
        if (returnDictionary) {
            NSLog(@"returnDictionary = %@", returnDictionary);
        } else {
            NSLog(@"error parsing JSON response: %@", parseError);
    
            NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"returnString = %@", returnString);
        }
    }
    
  2. I might suggest that you should use sendAsynchronousRequest, as shown above, rather than synchronous request, because you should never do synchronous requests from the main queue.

  3. My example PHP is doing minimal checking of the Content-type of the request, etc. So you might want to do more robust error handling.


我会尝试一下并让您知道。虽然上面的代码中没有显示,但我的 NSURLConnection 不在主线程上执行。方法 saveTrackToCloud 是异步调用的。 - ninefifteen
1
谢谢!我刚刚尝试了你的php代码,它解决了问题!昨天我花了好几个小时来解决这个问题。我想这可能是我的php代码有问题,因为我的php技能很低。 - ninefifteen
@Rob,使用$raw_post_data$_POST有什么区别吗?我似乎在使用其中一个时遇到了问题,详见我的问题说明:http://stackoverflow.com/q/41423343/2373410,请帮忙解答。 - Pangu
@Pangu - 是的,这是有区别的。这是回答中的主要观察点,即您不能使用$ _POST来处理JSON请求。您必须捕获原始请求并将其解码为json_decode - Rob

0

高级 REST 客户端 可以帮助您测试您的 Web 服务。因此,请确保您的 Web 服务按预期运行,然后在客户端应用程序中映射相同的参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接