Post HTTP di AngularJS su PHP e non definito


107

Ho un modulo con il tag ng-submit="login()

La funzione viene chiamata bene in 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');
        });
    }
}

Ricevo una risposta 200 OK dal file PHP, tuttavia, i dati restituiti lo dicono emaile passwordnon sono definiti. Questo è tutto il php che ho

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

Qualche idea del motivo per cui ottengo POSTvalori indefiniti ?

MODIFICARE

Volevo sottolineare poiché questa sembra essere una domanda popolare (eppure è vecchia), .successed .errorè stata deprecata e dovresti usarla .thencome ha sottolineato @James Gentes nei commenti


2
Hai guardato la scheda di rete dei tuoi strumenti di sviluppo? Quale valore viene trasmesso $http?
Marcel Korpel

1
Nella scheda della rete, sotto Form-Datac'è scritto{"email":"fsdg@sdf.com","password":"1234"}
Ronnie

@Ronnie sembra JSON. Prova print_r($_POST);e poi prova json_decode()sull'indice giusto
HamZa

1
echo 'test';funziona bene. Sto certamente indicando il file giusto
Ronnie

1
Nota che .success e .error sono stati deprecati e sostituiti con .then ( docs.angularjs.org/api/ng/service/$http )
James Gentes

Risposte:


228

angularjs .post()imposta come predefinito l'intestazione Content-type application/json. Stai sovrascrivendo questo per passare dati codificati in forma, tuttavia non stai modificando il tuo datavalore per passare una stringa di query appropriata, quindi PHP non viene popolato $_POSTcome previsto.

Il mio suggerimento sarebbe quello di utilizzare semplicemente l'impostazione angularjs predefinita di application/jsoncome intestazione, leggere l'input non elaborato in PHP e quindi deserializzare il JSON.

Ciò può essere ottenuto in PHP in questo modo:

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

In alternativa, se fai molto affidamento sulla $_POSTfunzionalità, puoi formare una stringa di query come email=someemail@email.com&password=somepassworde inviarla come dati. Assicurati che questa stringa di query sia codificata come URL. Se costruito manualmente (invece di usare qualcosa di simile jQuery.serialize()), Javascript encodeURIComponent()dovrebbe fare il trucco per te.


7
Non mancare di rispetto alle tue conoscenze, ma l'uso file_get_contents("php://input");sembra una specie di hack, no? Non ne ho mai sentito parlare. Cosa deve accadere in modo che possa fare riferimento ad esso come$_POST['email'];
Ronnie

6
@Ronnie Non è un hack. Dipende davvero da come desideri configurare il tuo servizio web. Se desideri inviare e recuperare JSON, devi lavorare con input $_POSTnon elaborato poiché non verrà popolato.
Mike Brant

1
@lepe Non mi è chiaro come la domanda / risposta collegata sia correlata alla mia risposta. Non vi è alcuna discussione sulla necessità di serializzare un oggetto javascript qui.
Mike Brant

2
@lascort non c'è davvero molta differenza nelle soluzioni. Nella mia soluzione, non sto popolando i dati in $ _POST, preferendo invece una variabile definita dall'utente. In generale, questo ha più senso per me in quanto quando si lavora con dati serializzati JSON, si potrebbe lavorare con oggetti o array con indicizzazione numerica. Non suggerirei di aggiungere un array indicizzato numericamente a $ _POST, poiché sarebbe un uso atipico. Generalmente evito anche di inserire dati in una qualsiasi delle superglobali utilizzate per i dati di input.
Mike Brant

1
@ ItsmeJulian non esiste una risposta assolutamente giusta. Potrebbe davvero dipendere dall'architettura della tua applicazione. Se stai interagendo con un servizio REST che sta consumando / fornendo JSON, allora probabilmente mi atterrei al tipo di contenuto JSON. Se lavorassi in gran parte con un endpoint che può produrre frammenti HTML o HTML o utilizza la pubblicazione di moduli di base come riserva per AJAX, allora potrei essere incline a rimanere con la codifica del modulo.
Mike Brant

41

Lo faccio sul lato server, all'inizio del mio file init, funziona come un incantesimo e non devi fare nulla in codice php angolare o esistente:

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

3
si dovrebbe lanci il risultato nel caso in cui $ _POST è vuoto: $_POST = (array) json_decode(file_get_contents('php://input'), true).
M'sieur Toph '12

Non capisco davvero perché i ragazzi di PHP non lo abbiano implementato da soli, si aspettano sempre post con codifica URL ??
azerafati

@ Bludream Non capisco perché qualcuno si aspetta che PHP faccia ciò che ci si aspetta. Viola il principio della minima sorpresa per tutto il tempo.
doug65536

Questo sembra un approccio molto fragile a meno che tu non sappia assolutamente che i dati inviati con POST rappresentano un array associativo (una rappresentazione di un oggetto in JSON). E se il JSON contenesse una rappresentazione di matrice indicizzata numericamente? $_POSTfinirebbe per ottenere un array indicizzato numericamente in questi casi, qualcosa che sarebbe un comportamento molto inaspettato in altre parti del sistema che si basano su un $_POSTcomportamento superglobale coerente .
Mike Brant

1
Lo uso solo in applicazioni ad alimentazione angolare, ovviamente, e convalido i miei dati POST in modo molto accurato, non vedo come possa essere un problema ...
valmarv

14

Nell'API che sto sviluppando ho un controller di base e all'interno del suo metodo __construct () ho quanto segue:

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

Ciò mi consente di fare semplicemente riferimento ai dati json come $ _POST ["var"] quando necessario. Funziona alla grande.

In questo modo, se un utente autenticato si connette a una libreria come jQuery che invia i dati dei post con un valore predefinito di Content-Type: application / x-www-form-urlencoded o Content-Type: application / json, l'API risponderà senza errori e lo farà rendere l'API un po 'più amichevole per gli sviluppatori.

Spero che questo ti aiuti.


11

Poiché PHP non accetta nativamente JSON, 'application/json'un approccio è aggiornare le intestazioni e i parametri da angolare in modo che l'API possa utilizzare direttamente i dati.

Innanzitutto , parametrizza i tuoi dati:

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

Quindi , aggiungi quanto segue al tuo file$http

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

Se tutte le tue richieste stanno andando a PHP, i parametri possono essere impostati a livello globale nella configurazione come segue:

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

8

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

        }]);

Codice lato server: -

<?php


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

?>

A causa del comportamento angolare non esiste un metodo diretto per il normale comportamento dei post sul server PHP, quindi devi gestirlo in oggetti json.


1
Questo non è corretto. Vedi le risposte sopra dove JSON viene letto direttamente dall'input non elaborato PHP. Questo è molto più semplice che mescolare JSON nella stringa di query.
Mike Brant

I metodi .successe .errorsono deprecati e sono stati rimossi dal framework AngularJS.
georgeawg

6

È necessario deserializzare i dati del modulo prima di passarli come secondo parametro a .post (). Puoi ottenere ciò utilizzando il metodo $ .param (data) di jQuery. Quindi sarai in grado sul lato server di fare riferimento ad esso come $ .POST ['email'];


6

Questa è la soluzione migliore (IMO) in quanto non richiede jQuery e nessuna decodifica JSON:

Fonte: https://wordpress.stackexchange.com/a/179373 e: https://stackoverflow.com/a/1714899/196507

Sommario:

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

Esempio:

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

Codice PHP:

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

Che dire: JSON.stringify('{ id: 'some_id', name : 'some_name' }')o $httpParamSerializerper la conversione lato client?
qrtLs

5

È una vecchia domanda, ma vale la pena ricordare che in Angular 1.4 viene aggiunto $ httpParamSerializer e quando si utilizza $ http.post, se usiamo $ httpParamSerializer (params) per passare i parametri, tutto funziona come una normale richiesta di post e nessuna deserializzazione JSON è necessario sul lato server.

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


1

Mi ci sono volute ore per capirlo mentre lavoravo con Angular e PHP. I dati del post non andavano su PHP in $ _POST

nel codice PHP eseguire le seguenti operazioni. - Crea una variabile $ angular_post_params - Quindi procedi come segue $angular_http_params = (array)json_decode(trim(file_get_contents('php://input')));

ora puoi accedere ai tuoi parametri come fai da $ _POST

$angular_http_params["key"]

nel caso ti stavi chiedendo di javascript .... questo è quello che ho usato

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

per i neofiti ... non dimenticare di aggiungere le direttive ng-app e ng-controller al contenitore del contenitore dei contenuti sulla pagina :)
Talha

I metodi .successe .errorsono deprecati e sono stati rimossi dal framework AngularJS.
georgeawg
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.