AngularJS - Qualche modo per $ http.post di inviare i parametri della richiesta invece di JSON?


116

Ho un vecchio codice che sta effettuando una richiesta AJAX POST tramite il metodo post di jQuery e assomiglia a questo:

$.post("/foo/bar", requestData,
    function(responseData)
    {
        //do stuff with response
    }

requestData è solo un oggetto javascript con alcune proprietà di stringa di base.

Sono in procinto di spostare le nostre cose per utilizzare Angular, e voglio sostituire questa chiamata con $ http.post. Mi è venuto in mente quanto segue:

$http.post("/foo/bar", requestData).success(
    function(responseData) {
        //do stuff with response
    }
});

Quando l'ho fatto, ho ricevuto una risposta di errore 500 dal server. Utilizzando Firebug, ho scoperto che questo inviava il corpo della richiesta in questo modo:

{"param1":"value1","param2":"value2","param3":"value3"}

Il jQuery di successo $.postinvia il corpo in questo modo:

param1=value1&param2=value2&param3=value3

L'endpoint che sto raggiungendo si aspetta parametri di richiesta e non JSON. Quindi, la mia domanda è che c'è comunque da dire $http.postdi inviare l'oggetto javascript come parametri di richiesta invece di JSON? Sì, so che potrei costruire io stesso la stringa dall'oggetto, ma voglio sapere se Angular fornisce qualcosa per questo fuori dagli schemi.

Risposte:


140

Penso che il paramsparametro di configurazione non funzionerà qui poiché aggiunge la stringa all'URL invece del corpo, ma per aggiungere a ciò che Infeligo ha suggerito qui è un esempio di override globale di una trasformazione predefinita (utilizzando jQuery param come esempio per convertire i dati alla stringa del parametro).

Imposta la funzione TransformRequest globale:

var app = angular.module('myApp');

app.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

In questo modo tutte le chiamate a $ http.post trasformeranno automaticamente il corpo nello stesso formato di parametro utilizzato dalla $.postchiamata jQuery .

Nota che potresti anche voler impostare l'intestazione Content-Type per chiamata o globalmente in questo modo:

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

TransformRequest non globale di esempio per chiamata:

    var transform = function(data){
        return $.param(data);
    }

    $http.post("/foo/bar", requestData, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        transformRequest: transform
    }).success(function(responseData) {
        //do stuff with response
    });

Mi chiedevo se ci fosse qualcosa di diverso dall'avere una funzione transformRequest, ma sembra che non ci sia. Grazie per aver avvertito la funzione jQuery param.
dnc253

Il metodo non globale per chiamata funziona bene per me, ma quando provo a configurarlo a livello globale tramite $httpProvider.defaults, allora non funziona, qualche indizio su questo?
Dfr

1
WRT configurandolo a livello globale, anch'io sto avendo problemi. Quando provo a farlo usando lo snippet fornito qui, ricevo un errore Cannot read property "jquery" of undefined.Come posso risolvere questo problema? PS. Le trasformazioni per chiamata funzionano.
kshep92

@ kshep92 Ciò che sta accadendo è che la funzione transformRequest viene chiamata su una richiesta senza dati, quindi "data" non è definita. Ho aggiunto una guardia prima di 'return $ .param (data);'. Inseriscilo come prima riga della funzione transformRequest: 'if (data === undefined) return data;' Guarda la modifica che ho apportato alla risposta.
Jere.Jones

1
a partire da Angular 1.4 puoi usare $ httpParamSerializer invece di jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
theRemix

21

Se usi Angular> = 1.4 , ecco la soluzione più pulita che ho trovato che non si basa su nulla di personalizzato o esterno:

angular.module('yourModule')
  .config(function ($httpProvider, $httpParamSerializerJQLikeProvider){
    $httpProvider.defaults.transformRequest.unshift($httpParamSerializerJQLikeProvider.$get());
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
});

E poi puoi farlo ovunque nella tua app:

$http({
  method: 'POST',
  url: '/requesturl',
  data: {
    param1: 'value1',
    param2: 'value2'
  }
});

Inoltre serializzerà correttamente i dati come param1=value1&param2=value2e li invierà /requesturlcon l' application/x-www-form-urlencoded; charset=utf-8intestazione Content-Type come normalmente previsto con le richieste POST sugli endpoint.


17

Dalla documentazione di AngularJS:

params - {Object.} - Mappa di stringhe o oggetti che verranno trasformati in? key1 = value1 & key2 = value2 dopo l'URL. Se il valore non è una stringa , sarà JSONified.

Quindi, fornire una stringa come parametri. Se non lo vuoi, usa le trasformazioni. Di nuovo, dalla documentazione:

Per eseguire l'override di queste trasformazioni localmente, specificare le funzioni di trasformazione come proprietà transformRequest e / o transformResponse dell'oggetto config. Per sovrascrivere globalmente le trasformazioni predefinite, sovrascrivi le proprietà $ httpProvider.defaults.transformRequest e $ httpProvider.defaults.transformResponse di $ httpProvider.

Fare riferimento alla documentazione per maggiori dettagli.


Ho visto i parametri nella documentazione e, come menziona Gloopy, ne ho bisogno nel corpo e non nell'URL. Mi chiedevo se ci fosse qualche opzione o qualcosa che mi mancava per fare i parametri invece di JSON, ma sembra che ho solo bisogno di usare la proprietà transformRequest.
dnc253

15

Usa la $.paramfunzione di jQuery per serializzare i dati JSON in requestData.

In breve, usando un codice simile al tuo:

$http.post("/foo/bar",
$.param(requestData),
{
    headers:
    {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    }
}
).success(
    function(responseData) {
        //do stuff with response
    }
});

Per usarlo, devi includere jQuery nella tua pagina insieme ad AngularJS.


7

Si noti che a partire da Angular 1.4, è possibile serializzare i dati del modulo senza utilizzare jQuery.

Nell'app.js:

module.run(function($http, $httpParamSerializerJQLike) {
  $http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});

Quindi nel tuo controller:

$http({
    method: 'POST',
    url: myUrl',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: myData
});

Questa risposta è ottima. Affronta i 2 problemi principali con Post di Angular. L'intestazione deve essere impostata correttamente e devi serializzare i dati json. Se non hai bisogno del supporto IE8 usa 1.4+ o successivo.
mbokil

L'ho appena implementato e risolve i problemi che stavo avendo con il post, ma questo cambia anche il modo in cui funziona la patch e sembra aver interrotto tutti i miei usi di $ http.patch ().
Mike Feltman

5

Questo potrebbe essere un trucco, ma ho evitato il problema e ho convertito il json nell'array POST di PHP sul lato server:

$_POST = json_decode(file_get_contents('php://input'), true);

Ho usato questo metodo, ma lo odio; e mi ci è voluto molto tempo per capire perché dovevo usarlo.
meconroy

come ho detto, sembra hacky. Come la maggior parte di php;)
TimoSolo

5

Ho anche problemi con l'impostazione dell'autenticazione http personalizzata perché $ resource memorizza la richiesta nella cache.

Per farlo funzionare devi sovrascrivere le intestazioni esistenti in questo modo

var transformRequest = function(data, headersGetter){
  var headers = headersGetter();
  headers['Authorization'] = 'WSSE profile="UsernameToken"';
  headers['X-WSSE'] = 'UsernameToken ' + nonce
  headers['Content-Type'] = 'application/json';
};

return $resource(
  url,
    {
    },
    {
      query: {
        method: 'POST',
        url: apiURL + '/profile',
        transformRequest: transformRequest,
        params: {userId: '@userId'}
      },
    }
);

Spero di essere stato in grado di aiutare qualcuno. Mi ci sono voluti 3 giorni per capire questo.


Immagino che tu mi abbia appena risparmiato 3 giorni di lavoro. Grazie!!! Sto ancora cercando di capire se posso intercettare la chiamata di richiesta in qualche modo in modo da poter inserire un'intestazione personalizzata per ogni chiamata.
marcoseu

4

Modifica le intestazioni predefinite:

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";

Quindi usa il $.parammetodo di JQuery :

var payload = $.param({key: value});
$http.post(targetURL, payload);

3
   .controller('pieChartController', ['$scope', '$http', '$httpParamSerializerJQLike', function($scope, $http, $httpParamSerializerJQLike) {
        var data = {
                TimeStamp : "2016-04-25 12:50:00"
        };
        $http({
            method: 'POST',
            url: 'serverutilizationreport',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            data: $httpParamSerializerJQLike(data),
        }).success(function () {});
    }
  ]);

Secondo me è più semplice e facile ... Potrebbero esserci molti altri modi
Rohit Luthra

2

Regolazione rapida: per quelli di voi che hanno problemi con la configurazione globale della funzione transformRequest, ecco lo snippet che sto usando per eliminare l' Cannot read property 'jquery' of undefinederrore:

$httpProvider.defaults.transformRequest = function(data) {
        return data != undefined ? $.param(data) : null;
    }


0

Ho trovato molte volte un comportamento problematico di tutto questo. L'ho usato da express (senza digitazioni) e bodyParser (con le digitazioni dt ~ body-parser).

Non ho provato a caricare un file, ma semplicemente a interpretare un JSON fornito in una stringa di post.

Il request.bodyera semplicemente un json vuoto ( {}).

Dopo molte indagini finalmente questo ha funzionato per me:

import { json } from 'body-parser';
...
app.use(json()); <-- should be defined before the first POST handler!

Potrebbe anche essere importante fornire il application/jsontipo di contenuto nella stringa della richiesta dal lato client.


Mi dispiace per la risposta in stile "e sacrifica una gallina nera", cosa purtroppo comune nella fase attuale dell'ambiente dattiloscritto / nodo / angolare.
peterh - Ripristina Monica il

0

Sintassi per AngularJS v1.4.8 + (v1.5.0)

       $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );

Per esempio:

    var url = "http://example.com";

    var data = {
        "param1": "value1",
        "param2": "value2",
        "param3": "value3"
    };

    var config = {
        headers: {
            'Content-Type': "application/json"
        }
    };

    $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );
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.