web-dev-qa-db-fra.com

AngularJS - Quel moyen pour $ http.post d’envoyer des paramètres de requête au lieu de JSON?

J'ai un ancien code qui fait une demande AJAX POST via la méthode post de jQuery et ressemble à ceci:

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

requestData est juste un objet javascript avec quelques propriétés de chaîne de base.

Je suis en train de transférer nos données pour utiliser Angular et je souhaite remplacer cet appel par $ http.post. Je suis venu avec ce qui suit:

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

Quand j'ai fait cela, j'ai reçu une réponse d'erreur 500 du serveur. En utilisant Firebug, j'ai trouvé que cela envoyait le corps de la requête comme ceci:

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

La bonne méthode jQuery $.post envoie le corps de la manière suivante:

param1=value1&param2=value2&param3=value3

Le terminal que je frappe attend des paramètres de requête et non JSON. Ma question est donc de savoir s'il est possible de demander à $http.post d'envoyer l'objet javascript en tant que paramètres de demande au lieu de JSON? Oui, je sais que je pourrais construire la chaîne moi-même à partir de l'objet, mais je veux savoir si Angular fournit quoi que ce soit pour cela hors de la boîte.

116
dnc253

Je pense que le paramètre params config ne fonctionnera pas ici puisqu'il ajoute la chaîne à l'URL au lieu du corps, mais il convient d'ajouter à ce qu'Infeligo a suggéré ici un exemple de substitution globale d'une transformation par défaut (avec jQuery param comme exemple pour convertir les données en chaîne de paramètres).

Configurer la fonction globale transformRequest:

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

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

Ainsi, tous les appels vers $ http.post transformeront automatiquement le corps dans le même format que celui utilisé par l'appel jQuery $.post.

Notez que vous pouvez également définir l'en-tête Content-Type par appel ou globalement, comme ceci:

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

Exemple de requête de transformation non globale par appel:

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

Si vous utilisez Angular> = 1.4 , voici la solution la plus propre que j'ai trouvée et qui ne repose sur aucun élément personnalisé ou externe:

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

Et ensuite, vous pouvez le faire n'importe où dans votre application:

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

Et il sérialise correctement les données en tant que param1=value1&param2=value2 et les envoie à /requesturl avec l'en-tête application/x-www-form-urlencoded; charset=utf-8 Content-Type comme il est normalement prévu avec les demandes POST sur les ordinateurs d'extrémité.

20
Saeb Amini

De la documentation AngularJS:

params - {Object.} - Carte des chaînes ou des objets qui sera transformé en? key1 = valeur1 & clé2 = valeur2 après l'URL. Si la valeur n'est pas une chaîne, ce sera JSONified.

Donc, fournissez une chaîne en tant que paramètres. Si vous ne le souhaitez pas, utilisez des transformations. Encore une fois, de la documentation:

Pour remplacer ces transformations localement, spécifiez les fonctions de transformation en tant que propriétés transformRequest et/ou transformResponse de la configuration objet. Pour remplacer globalement les transformations par défaut, remplacez le $ httpProvider.defaults.transformRequest et $ httpProvider.defaults.transformResponse propriétés du $ httpProvider.

Reportez-vous à documentation pour plus de détails.

17
Infeligo

Utilisez la fonction $.param de jQuery pour sérialiser les données JSON dans requestData.

En bref, en utilisant un code similaire au vôtre:

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

Pour utiliser cela, vous devez inclure jQuery dans votre page avec AngularJS.

15
Sagar Bhosale

Notez que depuis Angular 1.4, vous pouvez sérialiser les données de formulaire sans utiliser jQuery.

Dans les app.js:

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

Puis dans votre contrôleur:

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

La définition de l'authentification http personnalisée me pose également problème, car $ resource met la requête en cache.

Pour que cela fonctionne, vous devez écraser les en-têtes existants. 

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

J'espère que j'ai pu aider quelqu'un. Il m'a fallu 3 jours pour comprendre celui-ci.

5
Frank Marcelo

Cela pourrait être un peu un bidouillage, mais j'ai évité le problème et converti le JSON en tableau POST de PHP sur le serveur:

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

Modifier les en-têtes par défaut:

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

Ensuite, utilisez la méthode $.param de JQuery:

var payload = $.param({key: value});
$http.post(targetURL, payload);
4
Zags
   .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 () {});
    }
  ]);
3
Rohit Luthra

Réglage rapide - pour ceux qui ont des problèmes avec la configuration globale de la fonction transformRequest, voici l'extrait de code que j'utilise pour supprimer l'erreur Cannot read property 'jquery' of undefined:

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

Vous pouvez également résoudre ce problème sans changer de code sur le serveur, changer l'en-tête dans l'appel $http.post et utiliser $_POST de la manière habituelle. Expliqué ici: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

1
vikramaditya234

J'ai trouvé plusieurs fois un comportement problématique de cet ensemble. Je l'ai utilisé dans express (sans dactylographie) et dans bodyParser (avec les dt ~ body-analyseurs syntaxiques).

Je n'ai pas essayé de télécharger un fichier, mais simplement d'interpréter un JSON donné dans une chaîne de publication.

Le request.body était simplement un JSON vide ({}).

Après de nombreuses enquêtes, cela a finalement fonctionné pour moi:

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

Il peut également être important d'indiquer le type de contenu application/json dans la chaîne de demande du côté client.

0
peterh

Syntaxe pour AngularJS v1.4.8 + (v1.5.0)

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

Par exemple:

    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
                    }
            );
0
Pranav V R