ios — проблема формата JSON в PHP REST-сервисе, получающем POST от AFNetworking 2.0

У меня есть ситуация, когда я помещаю строку JSON из своего кода iOS, используя код AFNetworking 2.0. Мой клиентский код выглядит так:

NSURL *url = [NSURL URLWithString:BaseURLString];
NSString *jsonString = [[NSString alloc] initWithData:jsonPayloadForProject encoding:NSUTF8StringEncoding];

NSDictionary *parameters = @{@"project": jsonString};

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]       initWithBaseURL:url];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

[manager POST:@"service.php" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@", [responseObject description]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"POST JSON for Project Error"message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"OK"otherButtonTitles:nil];
[alertView show];
}];

JSON выглядит так:

{
"Maps" : [
{
"Markers" : [
{
"marker_tag" : -790386438,
"location_y" : 182,
"location_x" : 344
},
{
"marker_tag" : 451496476,
"location_y" : 267,
"location_x" : 150.5
}
],
"image_string" : "EC817509-DE49-4914-840E-5E407571F6AE.jpeg",
"order_num" : 0,
"name" : "Blah1",
"id" : "EC817509-DE49-4914-840E-5E407571F6AE"},
{
"Markers" : [
{
"marker_tag" : -79601351,
"location_y" : 377,
"location_x" : 486.5,
"image_id" : "Blah2",
"map_id" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A"}
],
"image_string" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A.jpeg",
"order_num" : 0,
"name" : "1st floor",
"id" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A"}
],
"longitude" : "-222.222222",
"latitude" : "33.33333"}

Когда я читаю строку JSON на сервере в своем PHP-коде, используя

$json_str = file_get_contents('php://input');

Когда я это делаю, я получаю следующую строку:

{ "project" = '{ \n \"Maps\" : [ \n { \n \"Markers\" : [ \n { \n \"marker_tag\n : = -790386438, \n ....

Мой вопрос заключается в том, что, когда я делаю следующее, я ничего не получаю.

$array_str = json_decode($json_str, true);

Каков наилучший способ поместить это в массив для анализа данных? Как я могу получить исходную строку JSON, которую я отправил с моего клиента?

1

Решение

Пара вопросов

  1. Ваш AFHTTPSessionManager использует по умолчанию AFJSONResponseSerializer но просто отменяет acceptableContentTypes, Это можно сделать только в том случае, если код вашего сервера действительно возвращает JSON и не указывает это в Content-Type заголовок.

    • Если сервер действительно не возвращает JSON, а не изменяет acceptableContentTypes, вы должны просто использовать AFHTTPSessionManager

      manager.responseSerializer = [AFHTTPResponseSerializer serializer];
      
    • или сервер должен вернуть JSON и убедиться, что он указывает правильное Content-Type заголовок:

      <?php
      
      $json_str = file_get_contents('php://input');
      $json = json_decode($json_str, true);
      
      header('Content-Type: application/json');
      
      $result = array("received" => $json);
      echo json_encode($result);
      
      ?>
      

      Сделав это, теперь я могу просто удалить acceptableContentTypes строка из клиентского кода в целом и продолжать использовать значение по умолчанию AFJSONResponseSerializer,

  2. Продемонстрированный механизм построения parameters это неверно. Вы создаете словарь JSON только с одним элементом, который сам по себе является строковым представлением JSON.

    Вместо того, чтобы помещать строковое представление в словарь, я бы посоветовал вам поместить в словарь реальный словарь. Итак, если у вас действительно есть NSData JSON, преобразовать его обратно во вложенный NSDictionary/NSArray состав:

    NSError *error;
    id jsonPayload = [NSJSONSerialization JSONObjectWithData:jsonPayloadData options:0 error:&error];
    NSAssert(jsonPayload, @"json parsing error: %@", error);
    
    NSDictionary *parameters = @{@"project": jsonPayload};
    

    Теперь, скорее всего, будет немного глупо создавать NSData с помощью dataWithJSONObjectтолько чтобы развернуться и извлечь его обратно, а вы бы просто использовать этот оригинал NSDictionary в parameters, но, надеюсь, это иллюстрирует суть.

Итак, собрав все это вместе, предполагая, что вы измените код сервера, чтобы он возвращал правильно отформатированный ответ JSON, как описано выше, клиентский код теперь становится:

NSError *error;
id jsonPayload = [NSJSONSerialization JSONObjectWithData:jsonPayloadData options:0 error:&error];
NSAssert(jsonPayload, @"json parsing error: %@", error);

NSDictionary *parameters = @{@"project": jsonPayload};

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

[manager POST:@"service.php" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@", [responseObject description]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"error=%@", error);
}];

Если вы сделаете это, вы успешно отправите свой JSON-запрос на сервер, он будет проанализирован, вставлен в новый ассоциативный массив, преобразован обратно в JSON и возвращен в клиентское приложение, которое будет использовать значение по умолчанию. AFJSONResponseSerializer разобрать и записать.

1

Другие решения

Других решений пока нет …