AngularJS HTTP повідомлення на PHP та невизначений


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 ОК з файлу PHP, однак повернені дані говорять про це emailі passwordне визначені. Це все, що у мене є

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

Будь-яка ідея, чому я отримую невизначені POSTзначення?

EDIT

Я хотів зазначити, оскільки це, мабуть, є популярним питанням (все ж воно давнє), .successі .errorвоно застаріле, і вам слід користуватися так, .thenяк @Games Gentes вказав у коментарях


2
Ви подивилися на вкладку мережі інструментів для розробників? Яке значення передається $http?
Marcel Korpel

1
На вкладці мережі під Form-Dataним написано{"email":"fsdg@sdf.com","password":"1234"}
Ronnie

@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()за замовчуванням містить заголовок типу Вміст 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

Я роблю це на стороні сервера, на початку мого файлу init працює як шарм, і вам не потрібно нічого робити в кутовому або існуючому 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-адресами?
azerafati

@Bludream Я не розумію, чому хтось очікує, що PHP зробить те, що очікується. Це порушує принцип найменшого здивування весь час.
doug65536

Це здається дуже крихким підходом, якщо ви абсолютно не знаєте, що дані POSTed являють собою асоціативний масив (представлення об'єкта в JSON). Що робити, якщо JSON містив числове індексування представлення масиву? $_POSTв кінцевому підсумку отримає числовий індексований масив у цьому випадку, що було б дуже несподіваною поведінкою в іншій частині системи, що покладається на послідовну $_POSTнадглобальну поведінку.
Майк Брант

1
Я, звичайно, використовую це лише у програмах з кутовим живленням, і я ретельно перевіряю свої поштові дані, не розумію, як це може бути проблемою ...
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'Один підхід - оновити заголовки та параметри з кутового, щоб 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

Демо-код кутового 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);

?>

Через кутову поведінку не існує прямого методу нормальної поведінки після публікації на сервері PHP, тому вам доведеться керувати нею в об'єктах json.


1
Це неправильно. Дивіться відповіді вище, де JSON зчитується безпосередньо з вихідних даних PHP. Це набагато простіше, ніж змішування JSON у рядок запиту.
Майк Брант

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

6

Вам потрібно дезаріалізувати дані форми, перш ніж передавати їх як другий параметр до .post (). Ви можете досягти цього за допомогою методу $ .param (data) jQuery. Тоді ви зможете на стороні сервера посилатись на нього як $ .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 (парами) для передачі параметрів, все працює як звичайний запит на пошту і жодна десаріалізація 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 до контейнера для
власників

Ці .successта .errorметоди застаріли і були видалені з рамок AngularJS.
georgeawg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.