AngularJS HTTP wysyła do PHP i jest niezdefiniowany


107

Mam formularz z tagiem ng-submit="login()

Funkcja jest nazywana w javascript dobrze.

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');
        });
    }
}

Otrzymuję odpowiedź 200 OK z powrotem z pliku PHP, jednak zwrócone dane mówią o tym emaili passwordsą niezdefiniowane. To wszystko, co mam php

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

Masz jakiś pomysł, dlaczego otrzymuję niezdefiniowane POSTwartości?

EDYTOWAĆ

Chciałem zwrócić uwagę, ponieważ wydaje się, że jest to popularne pytanie (ale jest stare) .successi .errorzostało wycofane i powinieneś używać, .thenjak wskazał @James Gentes w komentarzach


2
Czy spojrzałeś na kartę sieciową swoich narzędzi programistycznych? Jaka wartość jest przekazywana $http?
— Marcel Korpel

1
W zakładce sieci pod Form-Datanim jest napisane{"email":"fsdg@sdf.com","password":"1234"}
— Ronnie

@Ronnie Wygląda na JSON. Spróbuj, print_r($_POST);a potem spróbuj json_decode()na prawym indeksie
— HamZa

1
echo 'test';działa w porządku. Z pewnością wskazuję na właściwy plik
— Ronnie

1
Zauważ, że .success i .error zostały wycofane i zastąpione przez .then ( docs.angularjs.org/api/ng/service/$http )
— James Gentes,

Odpowiedzi:


228

angularjs .post()domyślnie ustawia nagłówek Content-Type na application/json. Zastępujesz to, aby przekazywać dane zakodowane w postaci, jednak nie zmieniasz datawartości, aby przekazać odpowiedni ciąg zapytania, więc PHP nie zapełnia się $_POSTzgodnie z oczekiwaniami.

Moja sugestia byłaby taka, aby po prostu użyć domyślnego ustawienia angularjs application/jsonjako nagłówek as, przeczytać nieprzetworzone dane wejściowe w PHP, a następnie deserializować JSON.

Można to osiągnąć w PHP w następujący sposób:

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

Alternatywnie, jeśli w dużym stopniu polegasz na $_POSTfunkcjonalności, możesz utworzyć ciąg zapytania, taki jak email=someemail@email.com&password=somepasswordi wysłać go jako dane. Upewnij się, że ten ciąg zapytania jest zakodowany w postaci adresu URL. Jeśli jest zbudowany ręcznie (w przeciwieństwie do czegoś podobnego jQuery.serialize()), Javascript encodeURIComponent()powinien załatwić sprawę za Ciebie.


7
Nie lekceważąc Twojej wiedzy, ale używanie file_get_contents("php://input");wydaje się trochę jak hack, prawda? Nigdy o tym nie słyszałem. Co musi się wydarzyć, abym mógł się do tego odnieść w stylu$_POST['email'];
— Ronnie

6
@Ronnie To nie jest hack. To naprawdę zależy od tego, jak chcesz skonfigurować usługę internetową. Jeśli chcesz wysyłać i pobierać dane JSON, musisz pracować z nieprzetworzonymi danymi wejściowymi, ponieważ $_POSTnie zostaną wypełnione.
— Mike Brant

1
@lepe Nie jest dla mnie jasne, jak powiązane pytanie / odpowiedź odnosi się do mojej odpowiedzi. Nie ma tutaj dyskusji o konieczności serializacji obiektu javascript.
— Mike Brant

2
@lascort naprawdę nie ma dużej różnicy w rozwiązaniach. W moim rozwiązaniu nie wypełniam danych w $ _POST, wolę zamiast tego zmienną zdefiniowaną przez użytkownika. Ogólnie rzecz biorąc, ma to dla mnie większy sens, ponieważ podczas pracy z danymi serializowanymi JSON możesz pracować z obiektami lub tablicami indeksowanymi numerycznie. Nie sugerowałbym dodawania tablicy indeksowanej numerycznie do $ _POST, ponieważ byłoby to nietypowe użycie. Generalnie unikam też umieszczania danych w żadnym z superglobali, które są używane do wprowadzania danych.
— Mike Brant

1
@ItsmeJulian nie ma absolutnie dobrej odpowiedzi. Może to naprawdę zależeć od tego, jak zaprojektowana jest Twoja aplikacja. Jeśli wchodzisz w interakcję z usługą REST, która konsumuje / dostarcza JSON, prawdopodobnie pozostałbym przy typie zawartości JSON. Jeśli pracowałem w dużej mierze z punktem końcowym, który może tworzyć fragmenty HTML lub HTML lub używa podstawowego wysyłania formularzy jako rozwiązania zastępczego do AJAX, mógłbym być skłonny trzymać się kodowania formularzy.
— Mike Brant

41

Robię to po stronie serwera, na początku mojego pliku init, działa jak urok i nie musisz nic robić w kątowym lub istniejącym kodzie php:

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

3
oddasz swój wynik w przypadku $ _POST jest pusty: $_POST = (array) json_decode(file_get_contents('php://input'), true).
— M'sieur Toph '12

Naprawdę nie rozumiem, dlaczego faceci z PHP nie zaimplementowali tego sami. Naprawdę oczekują zawsze postów z kodowaniem url?
— azerafati

@Bludream Nie rozumiem, dlaczego ktokolwiek oczekuje, że PHP robi to, czego się oczekuje. Cały czas narusza zasadę najmniejszego zaskoczenia.
— doug65536

Wydaje się, że jest to bardzo delikatne podejście, chyba że absolutnie wiesz, że dane POST reprezentują tablicę asocjacyjną (reprezentację obiektu w formacie JSON). A co, jeśli JSON zawiera numerycznie indeksowaną reprezentację tablicy? $_POSTw takich przypadkach skończyłoby się otrzymaniem tablicy indeksowanej numerycznie, co byłoby bardzo nieoczekiwanym zachowaniem w innej części systemu, która opiera się na spójnym $_POSTzachowaniu superglobalnym.
— Mike Brant

1
Oczywiście używam tego tylko w aplikacjach zasilanych kątowo i bardzo dokładnie weryfikuję moje dane POST, nie rozumiem, jak to może być problem ...
— valmarv

14

W API, które tworzę, mam kontroler podstawowy, a wewnątrz jego metody __construct () mam:

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));
}

To pozwala mi w razie potrzeby po prostu odwoływać się do danych json jako $ _POST ["var"]. Działa świetnie.

W ten sposób, jeśli uwierzytelniony użytkownik połączy się z biblioteką, taką jak jQuery, która wysyła dane postu z domyślnym Content-Type: application / x-www-form-urlencoded lub Content-Type: application / json, API odpowie bez błędów i uczynić API trochę bardziej przyjaznym dla programistów.

Mam nadzieję że to pomoże.


11

Ponieważ PHP natywnie nie akceptuje formatu JSON, 'application/json'jednym z podejść jest aktualizacja nagłówków i parametrów z angular, aby interfejs API mógł bezpośrednio używać danych.

Najpierw sparametryzuj swoje dane:

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

Następnie dodaj następujące elementy do swojego$http

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

Jeśli wszystkie żądania idą do PHP, parametry można ustawić globalnie w konfiguracji w następujący sposób:

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

8

Kod demonstracyjny 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);
        });

        }]);

Kod po stronie serwera: -

<?php


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

?>

Ze względu na zachowanie kątowe nie ma bezpośredniej metody normalnego zachowania postów na serwerze PHP, więc musisz zarządzać nimi w obiektach json.


1
To jest niepoprawne. Zobacz odpowiedzi powyżej, gdzie JSON jest odczytywany bezpośrednio z surowego wejścia PHP. Jest to znacznie prostsze niż mieszanie JSON w ciągu zapytania.
— Mike Brant

Te .successi .errormetody są wycofywane i usunięto z ramy angularjs.
— georgeawg

6

Musisz deserializować dane formularza przed przekazaniem ich jako drugiego parametru do .post (). Możesz to osiągnąć za pomocą metody $ .param (data) jQuery. Wtedy będziesz mógł odwoływać się do niego po stronie serwera jak $ .POST ['email'];


6

To najlepsze rozwiązanie (IMO), ponieważ nie wymaga jQuery ani dekodowania JSON:

Źródło: https://wordpress.stackexchange.com/a/179373 i: https://stackoverflow.com/a/1714899/196507

Podsumowanie:

//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';
});

Przykład:

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

Kod PHP:

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

A co z: JSON.stringify('{ id: 'some_id', name : 'some_name' }')czy w $httpParamSerializerprzypadku konwersji po stronie klienta?
— qrtLs


1

Zrozumienie tego zajęło mi wiele godzin podczas pracy z Angularem i PHP. Dane postu nie trafiały do ​​PHP w $ _POST

w kodzie PHP wykonaj następujące czynności. - Utwórz zmienną $ angular_post_params - Następnie wykonaj następujące czynności $angular_http_params = (array)json_decode(trim(file_get_contents('php://input')));

teraz możesz uzyskać dostęp do swoich parametrów, tak jak robisz to z $ _POST

$angular_http_params["key"]

w przypadku, gdy zastanawiałeś się nad javascript .... to jest to, czego użyłem

    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");
        });
    });

dla początkujących ... nie zapomnij mieć dyrektyw NG-app i NG-kontroler dodany do zawartości pojemnika uchwytem na stronie :)
— Talha

Te .successi .errormetody są wycofywane i usunięto z ramy angularjs.
— georgeawg
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.