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¶m2=value2¶m3=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.
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
});
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¶m2=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é.
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.
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.
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
});
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.
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);
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);
.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 () {});
}
]);
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;
}
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/
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.
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
}
);