Отправка вложенных форм данных на AJAX

Мне нужно отправить некоторые данные с помощью ajax и FormData, потому что я хочу отправить файл и некоторые другие параметры. Обычно я отправляю данные:

$.ajax({
    type:       'POST',
    url:        'some_url',
    dataType:   'json',
    processData:false,
    contentType:false,
    data:{
        Lvl_1-1: 'something',
        Lvl_1-2: 'something',
        Lvl_1-3: {
            Lvl_1-3-1: "something",
            Lvl_1-3-2: "something",
            Lvl_1-3-3: "something",
        },
    },
    ...
});

Если я не использую FormData(), у меня нет проблем, но при использовании FormData() только данные на Lvl1 в порядке, но что-то вложенное отображается как строка, подобная этой

<b>array</b> <i>(size=3)</i>
    'Lvl1-1' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>'Something'</font> 
        <i>(length=23)</i>
    'Lvl1-2' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>''Something''</font> <i>(length=3)</i>
    'Lvl1-3' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>'[object Object]'</font> <i>(length=17)</i>

Если я использую FormData() для кодирования данных внутри Lvl1-3 вместо [object Object], я получаю [object FormData]

Как мне получить массив вместо строки на Lvl1-3?

ПРИМЕЧАНИЕ. Если файл находится на верхнем уровне (Lvl_1), я могу отправить файл без проблем с помощью FormData(). Я не написал код прикрепленного файла, потому что это не проблема, вложенные данные. Я просто упомянул файл, потому что потому, что я использую FormData().

Ответ 1

URL-код Кодированные данные формы не имеют собственного способа выразить сложные структуры данных. Он поддерживает только пары с ключом = значение.

?foo=1&bar=2

Большинство библиотек синтаксического анализа данных позволяют массивы данных с использованием ключей с тем же именем

?foo=1&foo=2

PHP закрепил свой собственный синтаксис поверх этого формата:

?foo[]=1&foo[]=2

который допускал именованные ключи в ассоциативном массиве:

?foo[bar]=1&foo[baz]=2

и вложенные массивы:

?foo[bar][level2a]=1&foo[bar][level2b]=2

Из-за распространенности PHP jQuery принял этот синтаксис для генерации данных формы при передаче объекта JavaScript в data.

Если вы хотите использовать FormData, тогда jQuery не будет обрабатывать его для вас.

Эффект, который вы видите, заключается в том, что вы пытаетесь поместить объект (я предполагаю экземпляр FormData, но вы не показали эту часть своего кода) в качестве второго аргумента append - где строка ожидается.

Вам нужно сгенерировать имена ключей, используя синтаксис PHP самостоятельно.

form_data_instance.append("Lvl_1-3[Lvl_1-3-1]", "something");
form_data_instance.append("Lvl_1-3[Lvl_1-3-2]", "something");
form_data_instance.append("Lvl_1-3[Lvl_1-3-3]", "something");

Ответ 2

С моей стороны я упорядочиваю свои вложенные параметры и анализирую их на другом конце.

Например, если я хочу передать:

{"sthing":
  {"sthing":"sthing"},
  {"picture":
    {"legend":"great legend"},
    {"file":"great_picture.jpg"}
  }
}

Тогда я делаю:

// On the client side
const nestedParams = {"sthing":
                       {"sthing":"sthing"},
                       {"picture":
                         {"legend":"great legend"}
                       }
                     };
const pictureFile = document.querySelector('input[type="file"]')[0];
const formDataInstance = new FormData;
formDataInstance.append("nested_params": JSON.stringify(nested_params);
formDataInstance.append("file": document.querySelector('input[type="file"]')[0]);


// On the server side
params["nested_params"] = JSON.parse(params["nested_params"]);
params["nested_params"]["sthing"]["picture"]["file"] = params["file"];