Сообщение 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.