Сообщение HTTP AngularJS в PHP и undefined


107

У меня есть форма с тегом ng-submit="login()

Функция нормально вызывается в javascript.

function LoginForm($scope, $http)
{
    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

    $scope.email    = "fsdg@sdf.com";
    $scope.password = "1234";

    $scope.login = function()
    {
        data = {
            'email' : $scope.email,
            'password' : $scope.password
        };

        $http.post('resources/curl.php', data)
        .success(function(data, status, headers, config)
        {
            console.log(status + ' - ' + data);
        })
        .error(function(data, status, headers, config)
        {
            console.log('error');
        });
    }
}

Я получаю ответ 200 OK из файла PHP, однако возвращенные данные говорят об этом emailи passwordне определены. Это все, что у меня есть

<?php
$email = $_POST['email'];
$pass  = $_POST['password'];
echo $email;
?>

Есть идеи, почему я получаю неопределенные POSTзначения?

РЕДАКТИРОВАТЬ

Я хотел бы отметить, так как это , кажется, популярный вопрос (но это старый), .successи .errorустарели , и вы должны использовать в .thenкачестве @James Gentes отметил в commments


2
Вы смотрели вкладку сети в своих инструментах разработчика? Какое значение передается $http?
Marcel Korpel

1
Во вкладке сети под Form-Dataним написано{"email":"fsdg@sdf.com","password":"1234"}
Ронни

@Ronnie Похоже на JSON. Попробуй, print_r($_POST);а потом попробуй json_decode()правильный индекс
HamZa

1
echo 'test';работает отлично. Я определенно указываю на правильный файл
Ронни

1
Обратите внимание, что .success и .error устарели и заменены на .then ( docs.angularjs.org/api/ng/service/$http )
Джеймс

Ответы:


228

angularjs по .post()умолчанию использует заголовок Content-type как application/json. Вы переопределяете это для передачи данных в кодировке формы, однако вы не изменяете свое dataзначение для передачи соответствующей строки запроса, поэтому PHP не заполняется так, $_POSTкак вы ожидаете.

Я предлагаю просто использовать настройку angularjs по умолчанию в application/jsonкачестве заголовка, прочитать необработанный ввод в PHP, а затем десериализовать JSON.

В PHP это можно сделать так:

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
$email = $request->email;
$pass = $request->password;

В качестве альтернативы, если вы сильно полагаетесь на $_POSTфункциональность, вы можете сформировать строку запроса email=someemail@email.com&password=somepasswordи отправить ее как данные. Убедитесь, что эта строка запроса имеет кодировку URL. Если создается вручную (в отличие от использования чего-то вроде jQuery.serialize()), Javascript encodeURIComponent()должен помочь вам.


7
Не неуважение к вашим знаниям, но использование file_get_contents("php://input");похоже на взлом, не так ли? Я никогда об этом не слышал. Что должно произойти, чтобы я мог просто сослаться на это как$_POST['email'];
Ронни

6
@Ronnie Это не взлом. Это действительно зависит от того, как вы хотите настроить свой веб-сервис. Если вы хотите отправлять и получать JSON, вам нужно работать с необработанным вводом, поскольку $_POSTон не будет заполнен.
Майк Брант

1
@lepe Мне не ясно, как связанный вопрос / ответ соотносится с моим ответом. Здесь не обсуждается необходимость сериализации объекта javascript.
Майк Брант,

2
@lascort на самом деле нет большой разницы в решениях. В моем решении я не заполняю данные в $ _POST, вместо этого предпочитаю определяемую пользователем переменную. В общем, для меня это имеет больше смысла, поскольку при работе с сериализованными данными JSON вы можете работать с объектами или массивами с числовой индексацией. Я бы не предлагал добавлять массив с числовым индексом в $ _POST, так как это было бы нетипичным использованием. Я также обычно избегаю помещать данные в какие-либо суперглобальные переменные, которые используются для входных данных.
Майк Брант,

1
@ItsmeJulian нет абсолютно правильного ответа. Это может действительно зависеть от того, как устроено ваше приложение. Если вы взаимодействуете со службой REST, которая потребляет / доставляет JSON, я бы, вероятно, придерживался типа контента JSON. Если бы я работал в основном с конечной точкой, которая могла бы создавать HTML или HTML-фрагменты или использовать базовую публикацию форм в качестве альтернативы AJAX, тогда я мог бы быть склонен придерживаться кодирования форм.
Майк Брант

41

Я делаю это на стороне сервера, в начале моего файла инициализации, работает как шарм, и вам не нужно ничего делать в angular или существующем коде php:

if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST))
    $_POST = json_decode(file_get_contents('php://input'), true);

3
вы должны отдать свой результат в случае , если $ _POST пуст: $_POST = (array) json_decode(file_get_contents('php://input'), true).
M'sieur Toph '12

Я действительно не понимаю, почему ребята из PHP не реализовали это сами, они действительно всегда ожидают сообщений с кодировкой URL ??
азерафати

@Bludream Я не понимаю, почему кто-то ожидает от PHP того, что от него ожидается. Это все время нарушает принцип наименьшего удивления.
doug65536

Это кажется очень хрупким подходом, если вы абсолютно не знаете, что данные POSTed представляют собой ассоциативный массив (представление объекта в JSON). Что, если бы JSON содержал представление массива с числовым индексом? $_POSTв конечном итоге получился бы массив с числовой индексацией в этих случаях, что было бы очень неожиданным поведением в другой части системы, которая полагается на согласованное $_POSTсуперглобальное поведение.
Майк Брант,

1
Я, конечно, использую это только в приложениях, работающих на angular, и я очень тщательно проверяю свои данные POST, не понимаю, как это может быть проблемой ...
valmarv

14

В разрабатываемом мной API у меня есть базовый контроллер, а внутри его метода __construct () есть следующее:

if(isset($_SERVER["CONTENT_TYPE"]) && strpos($_SERVER["CONTENT_TYPE"], "application/json") !== false) {
    $_POST = array_merge($_POST, (array) json_decode(trim(file_get_contents('php://input')), true));
}

Это позволяет мне просто ссылаться на данные json как на $ _POST ["var"], когда это необходимо. Прекрасно работает.

Таким образом, если аутентифицированный пользователь подключается к библиотеке, такой как jQuery, которая отправляет данные сообщения со значением по умолчанию Content-Type: application / x-www-form-urlencoded или Content-Type: application / json, API ответит без ошибок и будет сделать API немного более удобным для разработчиков.

Надеюсь это поможет.


11

Поскольку PHP изначально не принимает JSON, 'application/json'один из подходов состоит в том, чтобы обновить ваши заголовки и параметры из angular, чтобы ваш api мог напрямую использовать данные.

Во-первых , параметризуйте свои данные:

data: $.param({ "foo": $scope.fooValue })

Затем добавьте в свой$http

 headers: {
     'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
 }, 

Если все ваши запросы отправляются на PHP, параметры могут быть установлены глобально в конфигурации следующим образом:

myApp.config(function($httpProvider) {
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});

8

Демонстрационный код Angular Js: -

angular.module('ModuleName',[]).controller('main', ['$http', function($http){

                var formData = { password: 'test pwd', email : 'test email' };
                var postData = 'myData='+JSON.stringify(formData);
                $http({
                        method : 'POST',
                        url : 'resources/curl.php',
                        data: postData,
                        headers : {'Content-Type': 'application/x-www-form-urlencoded'}  

                }).success(function(res){
                        console.log(res);
                }).error(function(error){
                        console.log(error);
        });

        }]);

Код на стороне сервера: -

<?php


// it will print whole json string, which you access after json_decocde in php
$myData = json_decode($_POST['myData']);
print_r($myData);

?>

Из-за поведения angular нет прямого метода для нормального поведения публикации на сервере PHP, поэтому вам нужно управлять им в объектах json.


1
Это неверно. См. Ответы выше, где JSON считывается непосредственно из исходных данных PHP. Это намного проще, чем смешивать JSON в строке запроса.
Майк Брант,

Эти .successи .errorметоды устарели и были удалены из рамок AngularJS.
georgeawg

6

Вам необходимо десериализовать данные формы, прежде чем передавать их в качестве второго параметра в .post (). Вы можете добиться этого, используя метод jQuery $ .param (data). Тогда вы сможете на стороне сервера ссылаться на него как $ .POST ['email'];


6

Это лучшее решение (IMO), поскольку оно не требует jQuery и декодирования JSON:

Источник: https://wordpress.stackexchange.com/a/179373 и: https://stackoverflow.com/a/1714899/196507

Резюме:

//Replacement of jQuery.param
var serialize = function(obj, prefix) {
  var str = [];
  for(var p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
      str.push(typeof v == "object" ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
};

//Your AngularJS application:
var app = angular.module('foo', []);

app.config(function ($httpProvider) {
    // send all requests payload as query string
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return serialize(data);
    };

    // set all post requests content type
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});

Пример:

...
   var data = { id: 'some_id', name : 'some_name' };
   $http.post(my_php_url,data).success(function(data){
        // It works!
   }).error(function() {
        // :(
   });

Код PHP:

<?php
    $id = $_POST["id"];
?>

Что насчет: JSON.stringify('{ id: 'some_id', name : 'some_name' }')или $httpParamSerializerдля преобразования на стороне клиента?
qrtLs

5

Это старый вопрос, но стоит упомянуть, что в Angular 1.4 добавлен $ httpParamSerializer, а при использовании $ http.post, если мы используем $ httpParamSerializer (params) для передачи параметров, все работает как обычный почтовый запрос, и десериализация JSON не выполняется. необходимо на стороне сервера.

https://docs.angularjs.org/api/ng/service/$httpParamSerializer


1

Мне потребовались часы, чтобы понять это при работе с Angular и PHP. Данные публикации не отправлялись в PHP в $ _POST

в PHP-коде сделайте следующее. - Создайте переменную $ angular_post_params - Затем сделайте следующее $angular_http_params = (array)json_decode(trim(file_get_contents('php://input')));

теперь вы можете получить доступ к своим параметрам, как из $ _POST

$angular_http_params["key"]

в случае, если вам было интересно о javascript .... это то, что я использовал

    var myApp = angular.module('appUsers', []);
    //var post_params = $.param({ request_type: "getListOfUsersWithRolesInfo" });
    var dataObj = {
        task_to_perform: 'getListOfUsersWithRolesInfo'
    };

    myApp.controller('ctrlListOfUsers', function ($scope, $http) {
        $http({
            method: 'POST',
            dataType: 'json',
            url: ajax_processor_url,
            headers: {
                'Content-Type': 'application/json'
            },
            data: dataObj,
            //transformRequest: function(){},
            timeout: 30000,
            cache: false
        }).
        success(function (rsp) {
            console.log("success");
            console.log(rsp);
        }).
        error(function (rsp) {
            console.log("error");
        });
    });

для новичков ... не забудьте добавить директивы ng-app и ng-controller к вашему контейнеру содержимого на странице :)
Talha

Эти .successи .errorметоды устарели и были удалены из рамок AngularJS.
georgeawg
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.