Comment puis-je afficher des données sous forme de données au lieu d'une demande de charge utile?
dans le code ci-dessous, la méthode AngularJS $http
appelle L'URL, et soumet l'objet xsrf comme" Request Payload " (comme décrit dans L'onglet Réseau du débogueur Chrome). La méthode jQuery $.ajax
fait le même appel, mais soumet xsrf comme"Form Data".
Comment puis-je faire soumettre des AngularJS xsrf comme données de formulaire au lieu d'une charge utile de demande?
var url = 'http://somewhere.com/';
var xsrf = {fkey: 'xsrf key'};
$http({
method: 'POST',
url: url,
data: xsrf
}).success(function () {});
$.ajax({
type: 'POST',
url: url,
data: xsrf,
dataType: 'json',
success: function() {}
});
22 réponses
la ligne suivante doit être ajoutée à l'objet $http qui est passé:
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
et les données transmises doivent être converties en une chaîne de caractères encodée par URL:
> $.param({fkey: "key"})
'fkey=key'
donc vous avez quelque chose comme:
$http({
method: 'POST',
url: url,
data: $.param({fkey: "key"}),
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})
de: https://groups.google.com/forum/#!msg / angular/5nAedJ1LyO0/4vj_72ezcdj
UPDATE
pour utiliser de nouveaux services ajouté avec AngularJS V1.4, Voir
Si vous ne voulez pas utiliser jQuery dans la solution, vous pouvez essayer ce. Solution retenue d'ici https://stackoverflow.com/a/1714899/1784301
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: xsrf
}).success(function () {});
la confusion persistante entourant cette question m'a inspiré à écrire un billet de blog à ce sujet. La solution que je propose dans ce post est meilleure que votre solution actuelle top rated parce qu'elle ne vous limite pas à paramétrer votre objet de données pour les appels de service $http; i.e. avec ma solution, vous pouvez simplement continuer à passer des objets de données réels à $http.post(), etc. et encore obtenir le résultat souhaité.
aussi, la réponse la mieux cotée repose sur l'inclusion de la pleine jQuery dans la page pour les $.param () fonction, alors que ma solution est agnostique jQuery, AngularJS pur prêt.
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax /
Espérons que cette aide.
j'ai pris quelques-unes des autres réponses et fait quelque chose d'un peu plus propre, mettre ce .config()
appel à la fin de votre angle.module dans votre application.js:
.config(['$httpProvider', function ($httpProvider) {
// Intercept POST requests, convert to standard form encoding
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
var key, result = [];
if (typeof data === "string")
return data;
for (key in data) {
if (data.hasOwnProperty(key))
result.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
}
return result.join("&");
});
}]);
As of AngularJS v1.4.0, Il existe un service $httpParamSerializer
intégré qui convertit n'importe quel objet en une partie D'une requête HTTP selon les règles qui sont énumérées sur la page docs .
Il peut être utilisé comme ceci:
$http.post('http://example.com', $httpParamSerializer(formDataObj)).
success(function(data){/* response status 200-299 */}).
error(function(data){/* response status 400-999 */});
rappelez-vous que pour un message de formulaire correct, l'en-tête Content-Type
doit être changé. Pour ce faire globalement pour toutes les requêtes POST, ce code (tiré de la demi-réponse D'Albireo) peut être utilisé:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
pour ce faire uniquement pour le post courant, la propriété headers
de la requête-objet doit être modifiée:
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: $httpParamSerializer(formDataObj)
};
$http(req);
vous pouvez définir le comportement globalement:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
donc vous n'avez pas à le redéfinir à chaque fois:
$http.post("/handle/post", {
foo: "FOO",
bar: "BAR"
}).success(function (data, status, headers, config) {
// TODO
}).error(function (data, status, headers, config) {
// TODO
});
comme une solution de contournement, vous pouvez simplement faire le code qui reçoit le message Répondre aux données application/json. Pour PHP j'ai ajouté le code ci-dessous, me permettant de le poster soit en forme-encodé ou JSON.
//handles JSON posted arguments and stuffs them into $_POST
//angular's $http makes JSON posts (not normal "form encoded")
$content_type_args = explode(';', $_SERVER['CONTENT_TYPE']); //parse content_type string
if ($content_type_args[0] == 'application/json')
$_POST = json_decode(file_get_contents('php://input'),true);
//now continue to reference $_POST vars as usual
ces réponses ressemblent à de la folie excessive, parfois, simple est juste mieux:
$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
"&password=" + encodeURIComponent(password) +
"&grant_type=password"
).success(function (data) {
//...
vous pouvez essayer avec la solution ci-dessous
$http({
method: 'POST',
url: url-post,
data: data-post-object-json,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for (var key in obj) {
if (obj[key] instanceof Array) {
for(var idx in obj[key]){
var subObj = obj[key][idx];
for(var subKey in subObj){
str.push(encodeURIComponent(key) + "[" + idx + "][" + encodeURIComponent(subKey) + "]=" + encodeURIComponent(subObj[subKey]));
}
}
}
else {
str.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
}
}
return str.join("&");
}
}).success(function(response) {
/* Do something */
});
créer un service d'adaptateur pour la poste:
services.service('Http', function ($http) {
var self = this
this.post = function (url, data) {
return $http({
method: 'POST',
url: url,
data: $.param(data),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
}
})
utilisez - le dans vos contrôleurs ou autre:
ctrls.controller('PersonCtrl', function (Http /* our service */) {
var self = this
self.user = {name: "Ozgur", eMail: null}
self.register = function () {
Http.post('/user/register', self.user).then(function (r) {
//response
console.log(r)
})
}
})
il y a un très joli tutoriel qui passe en revue ce sujet et d'autres choses connexes - soumettre des formulaires AJAX: la voie AngularJS .
fondamentalement, vous devez définir l'en-tête de la demande de poste pour indiquer que vous envoyez des données de formulaire comme une chaîne de caractères encodée URL, et de définir les données à envoyer le même format
$http({
method : 'POST',
url : 'url',
data : $.param(xsrf), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
});
notez que la fonction d'aide param() de jQuery est utilisée ici pour sérialiser les données dans une chaîne, mais vous pouvez le faire manuellement si vous n'utilisez pas jQuery.
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
please check out! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
pour les utilisateurs de Symfony2:
si vous ne voulez pas changer quoi que ce soit dans votre javascript pour que cela fonctionne, vous pouvez faire ces modifications dans votre application symfony:
créer une classe qui étend Symfony\Component\HttpFoundation\Request class:
<?php
namespace Acme\Test\MyRequest;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
class MyRequest extends Request{
/**
* Override and extend the createFromGlobals function.
*
*
*
* @return Request A new request
*
* @api
*/
public static function createFromGlobals()
{
// Get what we would get from the parent
$request = parent::createFromGlobals();
// Add the handling for 'application/json' content type.
if(0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/json')){
// The json is in the content
$cont = $request->getContent();
$json = json_decode($cont);
// ParameterBag must be an Array.
if(is_object($json)) {
$json = (array) $json;
}
$request->request = new ParameterBag($json);
}
return $request;
}
}
utilisez maintenant votre classe dans app_dev.php (ou tout fichier d'index que vous utilisez)
// web/app_dev.php
$kernel = new AppKernel('dev', true);
// $kernel->loadClassCache();
$request = ForumBundleRequest::createFromGlobals();
// use your class instead
// $request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
il ne suffit pas de définir le type de contenu, l'url encodent les données du formulaire avant l'envoi.
$http.post(url, jQuery.param(data))
j'utilise actuellement la solution suivante i trouvé dans le groupe Google AngularJS.
$http .post('/echo/json/', 'json=' + encodeURIComponent(angular.toJson(data)), { headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }).success(function(data) { $scope.data = data; });
notez que si vous utilisez PHP, vous devrez utiliser quelque chose comme le composant HTTP Request::createFromGlobals()
de Symfony 2 pour lire ceci, car $_POST ne sera pas automatiquement chargé avec.
AngularJS le fait correctement en faisant le type de contenu suivant à l'intérieur de l'en-tête http-request:
Content-Type: application/json
si vous allez avec php comme moi, ou même avec Symfony2 vous pouvez simplement étendre votre compatibilité de serveur pour la norme json comme décrit ici: http://silex.sensiolabs.org/doc/cookbook/json_request_body.html
La Symfony2 (par exemple à l'intérieur de votre DefaultController):
$request = $this->getRequest();
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
$data = json_decode($request->getContent(), true);
$request->request->replace(is_array($data) ? $data : array());
}
var_dump($request->request->all());
l'avantage serait, que vous n'avez pas besoin d'utiliser jQuery param et vous pourriez utiliser AngularJS sa façon native de faire de telles requêtes.
réponse complète (depuis l'angle 1,4). Vous devez inclure la dépendance $httpParamSerializer
var res = $resource(serverUrl + 'Token', { }, {
save: { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
});
res.save({ }, $httpParamSerializer({ param1: 'sdsd', param2: 'sdsd' }), function (response) {
}, function (error) {
});
dans votre application config -
$httpProvider.defaults.transformRequest = function (data) {
if (data === undefined)
return data;
var clonedData = $.extend(true, {}, data);
for (var property in clonedData)
if (property.substr(0, 1) == '$')
delete clonedData[property];
return $.param(clonedData);
};
Avec votre demande de ressource -
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
ce n'est pas une réponse directe, mais plutôt une direction de conception légèrement différente:
ne pas afficher les données comme une forme, mais comme un objet JSON pour être directement mappé à un objet côté serveur, ou utiliser la variable REST style path
maintenant je sais qu'aucune option ne pourrait être appropriée dans votre cas puisque vous essayez de passer une clé XSRF. Le Mapping dans une variable de chemin comme celle-ci est un dessin terrible:
http://www.someexample.com/xsrf/{xsrfKey}
parce que par nature vous voudriez passer la touche xsrf à d'autres chemins aussi, /login
, /book-appointment
etc. et vous ne voulez pas gâcher votre URL jolie
il est intéressant de l'ajouter comme champ objet n'est pas approprié non plus, parce que maintenant sur chacun des objets json que vous passez au serveur vous devez ajouter le champ
{
appointmentId : 23,
name : 'Joe Citizen',
xsrf : '...'
}
vous ne voulez certainement pas ajouter un autre champ sur votre classe côté serveur qui n'a pas d'association sémantique directe avec le domaine de l'objet.
à mon avis, la meilleure façon de passer votre clé xsrf est via un en-tête HTTP. De nombreuses bibliothèques de cadres web Côté Serveur de protection XSRF prennent en charge cette fonction. par exemple en Java Spring, vous pouvez le passer en utilisant X-CSRF-TOKEN
en-tête .
excellente capacité D'Angular de lier l'objet JS à L'objet UI signifie que nous pouvons nous débarrasser de la pratique de poster forme tous ensemble, et post JSON à la place. JSON peut être facilement dé-sérialisé dans l'objet côté serveur et soutient des structures de données complexes telles que la carte, les tableaux, les objets imbriqués, etc.
Comment afficher un tableau dans un formulaire de charge utile? Peut-être comme ceci:
shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday
ou ceci:
shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday
tous les deux sont de mauvaise conception..
C'est ce que je fais pour répondre à mes besoins, où je dois envoyer les données de connexion à L'API comme données de forme et L'objet Javascript (userData) est converti automatiquement en données encodées URL
var deferred = $q.defer();
$http({
method: 'POST',
url: apiserver + '/authenticate',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: userData
}).success(function (response) {
//logics
deferred.resolve(response);
}).error(function (err, status) {
deferred.reject(err);
});
Ce comment mon Userdata est
var userData = {
grant_type: 'password',
username: loginData.userName,
password: loginData.password
}
la seule chose que vous devez changer est d'utiliser la propriété "params" plutôt que" data "lorsque vous créez votre objet $http:
$http({
method: 'POST',
url: serviceUrl + '/ClientUpdate',
params: { LangUserId: userId, clientJSON: clients[i] },
})
dans l'exemple ci-dessus clients[i] est juste un objet JSON (non sérialisé d'une quelconque manière). Si vous utilisez "params" plutôt que" data "angular va sérialiser l'objet pour vous en utilisant $httpParamSerializer: https://docs.angularjs.org/api/ng/service/ $httpParamSerializer
utiliser AngularJS $http
service et utiliser sa post
méthode ou configurer $http
fonction.