Ajax-вызов с contentType: "application/json" не работает

У меня есть вызов ajax, который отправляет данные формы в php-функцию. Поскольку я много читаю, что использование contentType: 'application/json' - лучшая практика, я тоже хотел попробовать. Но, к сожалению, мой script ничего не возвращает, когда я его использую. Если я удалю его, script сделает то, что он должен делать.

Есть ли у вас какие-либо идеи, какова причина и почему? Спасибо!

$('#Form').submit(function(e) {
            e.preventDefault();

            var content = $(this).serialize() + "&ajax=1";

            $.ajax('app/class/controller/contactForm.php', {
              type: "POST",
              //contentType: 'application/json',
              dataType: 'json',
              data: content,
              success: function(result) {
                  console.log(result);
              }
            });
        })

и мой PHP:

if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    echo json_encode(validateForm($_POST));
}

Ответ 1

При использовании contentType: 'application/json' вы не сможете полагаться на заполненный $_POST. $_POST заполняется только для типов содержимого с кодировкой формы.

Таким образом, вам нужно прочитать свои данные из исходного ввода PHP следующим образом:

$input = file_get_contents('php://input');
$object = json_decode($input);

Конечно, если вы хотите отправить application/json, вы действительно должны отправить JSON, который вы не делаете. Вам либо нужно напрямую построить сериализацию объекта в JSON, либо вам нужно сделать что-то вроде этого - Преобразовать данные формы в объект JavaScript с помощью jQuery - сериализовать объект из форма.

Честно говоря, в вашем случае, поскольку вы имеете дело с данными формы, я не совсем думаю, что используется прецедент для использования application/json.

Ответ 2

Лучшей практикой, о которой вы говорите, является сервер script, устанавливающий Content-Type для JSON в "application/json":

Header('Content-Type: application/json; charset=UTF8');

Это связано с тем, что в противном случае будет отправлено сообщение по умолчанию Content-Type, чаще всего "catch-all" text/html, и это может привести к непониманию с клиентом.

Если вы не указываете себе Content-Type в запросе jQuery, jQuery определит наиболее подходящий. Проблема здесь в том, что вы отправляете форму POST, для которой по умолчанию Content-Type установлен jQuery is application/x-www-form-urlencoded, который сообщает PHP, чтобы декодировать данные как поля POST и заполнить $_POST. Тогда ваш script восстановил бы свои параметры от $_POST (или, может быть, $_REQUEST).

Изменив его на application/json, $_POST больше не будет заполнено, принимающая операция script не получит параметры, в которых она ожидала, и операция прерывается.

Итак, вам либо нужно:

  • не указывать сам Content-Type (лучше, IMHO)
  • установите тип содержимого application/x-www-form-urlencoded; charset=UTF-8
  • установить Content-Type application/json; charset=UTF-8 и изменить script для анализа потока POST и декодирования данных JSON; см. этот ответ.

Третий вариант требует правильной обработки php://input.

Ответ 3

PHP скрипт должен устанавливать заголовок Content-Type.

if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    header('Content-Type: application/json');
    echo json_encode(validateForm($_POST));
}