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.