Comment puis-je POSTER des données de formulaire encodées en url avec $ http sans jQuery?

195

Je suis nouveau sur AngularJS, et pour commencer, j'ai pensé développer une nouvelle application utilisant uniquement AngularJS.

J'essaie de faire un appel AJAX côté serveur, à l'aide $httpde mon application angulaire.

Pour envoyer les paramètres, j'ai essayé ce qui suit:

$http({
    method: "post",
    url: URL,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: $.param({username: $scope.userName, password: $scope.password})
}).success(function(result){
    console.log(result);
});

Cela fonctionne, mais il utilise également jQuery sur $.param. Pour supprimer la dépendance sur jQuery, j'ai essayé:

data: {username: $scope.userName, password: $scope.password}

mais cela semblait échouer. J'ai ensuite essayé params:

params: {username: $scope.userName, password: $scope.password}

mais cela a également semblé échouer. J'ai ensuite essayé JSON.stringify:

data: JSON.stringify({username: $scope.userName, password: $scope.password})

J'ai trouvé ces réponses possibles à ma quête, mais sans succès. Est-ce que je fais quelque chose de mal? Je suis sûr qu'AngularJS fournirait cette fonctionnalité, mais comment?

Veer Shrivastav
la source
Je ne sais pas quel est le problème réel, mais avez-vous essayé cela$http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});
Mritunjay
1
Votre première méthode devrait fonctionner, est $scope.userNamedéfinie? pourquoi n'avez-vous pas essayé data: data?
Kevin B
@KevinB: désolé .. J'ai fait le bon montage.
Veer Shrivastav
@mritunjay: désolé .. J'ai fait le montage .. J'essayais la même chose.
Veer Shrivastav
@Veer a-t-il fonctionné ou avez-vous toujours des problèmes?
V31

Réponses:

409

Je pense que vous devez faire est de transformer vos données d'objet non pas en chaîne JSON, mais en paramètres url.

Sur le blog de Ben Nadel .

Par défaut, le service $ http transformera la demande sortante en sérialisant les données en JSON puis en les affichant avec le type de contenu "application / json". Lorsque nous voulons publier la valeur en tant que publication FORM, nous devons modifier l'algorithme de sérialisation et publier les données avec le type de contenu, "application / x-www-form-urlencoded".

Exemple d'ici .

$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: {username: $scope.userName, password: $scope.password}
}).then(function () {});

METTRE À JOUR

Pour utiliser les nouveaux services ajoutés avec AngularJS V1.4, consultez

allenhwkim
la source
41
Merci de ne pas utiliser JQuery!
OverMars
1
que se passe-t-il si je dois soumettre des données en plusieurs parties / formulaires?
Dejell
2
Tant que les angles angulaires sont intégrés à jqLite angular.element, vous pouvez simplementreturn angular.element.param(obj);
Vicary
4
@Vicary Gardez à l'esprit que param () n'est pas implémenté dans jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.element
Alex Pavlov
1
c'est une autre façon de procéder var obj = {a: 1, b: 2}; Object.keys(obj).reduce(function(p, c) { return p.concat([encodeURIComponent(c) + "=" + encodeURIComponent(obj[c])]); }, []).join('&');
test30
136

Variables de codage d'URL utilisant uniquement les services AngularJS

Avec AngularJS 1.4 et versions ultérieures, deux services peuvent gérer le processus de codage d'url des données pour les requêtes POST, éliminant ainsi la nécessité de manipuler les données avec transformRequestou en utilisant des dépendances externes comme jQuery:

  1. $httpParamSerializerJQLike- un sérialiseur inspiré de jQuery .param()( recommandé )

  2. $httpParamSerializer - un sérialiseur utilisé par Angular lui-même pour les requêtes GET

Exemple d'utilisation

$http({
  url: 'some/api/endpoint',
  method: 'POST',
  data: $httpParamSerializerJQLike($scope.appForm.data), // Make sure to inject the service you choose to the controller
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
  }
}).then(function(response) { /* do something here */ });

Voir une démo Plunker plus détaillée


Comment sont $httpParamSerializerJQLikeet $httpParamSerializerdifférents

En général, il semble $httpParamSerializerutiliser un format de codage d'URL moins "traditionnel" que $httpParamSerializerJQLikelorsqu'il s'agit de structures de données complexes.

Par exemple (en ignorant le pourcentage de codage des crochets):

Encodage d'un tableau

{sites:['google', 'Facebook']} // Object with array property

sites[]=google&sites[]=facebook // Result with $httpParamSerializerJQLike

sites=google&sites=facebook // Result with $httpParamSerializer

Encodage d'un objet

{address: {city: 'LA', country: 'USA'}} // Object with object property

address[city]=LA&address[country]=USA // Result with $httpParamSerializerJQLike

address={"city": "LA", country: "USA"} // Result with $httpParamSerializer
Boaz
la source
Comment pouvons-nous utiliser cela sur $ resource dans une usine?
nature morte
2
Devrait être $http.({...au lieu de`$http.post({...
Carlos Granados
@CarlosGranados Merci d'avoir remarqué. Correction de cette faute de frappe ici et dans la démo de Plunker.
Boaz
Cela a parfaitement fonctionné après la migration de jQuery vers AngularJS
zero298
4
C'est la réponse spécifique à AngularJS que je cherchais. Je souhaite que l'affiche choisisse ceci comme la meilleure réponse.
Marty Chang
61

Tous ces éléments semblent exagérés (ou ne fonctionnent pas) ... faites simplement ceci:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Serj Sagan
la source
11
Enfin du bon sens
jlewkovich
Cela n'enverra-t-il pas la demande avec le mauvais en-tête de type de contenu?
Phil
Cela a fonctionné pour moi ... je ne sais pas ce que l'en-tête était, mais la demande a fonctionné et elle a permis de s'authentifier avec succès. Pourquoi ne pas le tester et nous le faire savoir.
Serj Sagan
5
@Phil Je suppose que cela pourrait dépendre du serveur, j'ai reçu une mauvaise demande, jusqu'à ce que j'ajoute {headers: {'Content-Type': 'application / x-www-form-urlencoded'}} comme argument de configuration ou utilisation de l'offre le constructeur $ http (config) comme la réponse de moices le montre. Quoi qu'il en soit, cela est supérieur à la réponse acceptée car il n'introduit pas de transformation magique et ne nécessite pas l'utilisateur d'un service auxiliaire. Merci!
M. Bungle
23

Le problème est le format de chaîne JSON, vous pouvez utiliser une chaîne URL simple dans les données:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
moices
la source
7
vous devez utiliser encodeURIComponent($scope.userName)pour encoder les données par URL ou vos paramètres seront corrompus si l'utilisateur entre une valeur comme"&myCustomParam=1"
Ivan Hušnjak
2
c'est la seule réponse qui a fonctionné pour moi! J'ai sauté le succès, mais le format $ http est bon
xenteros
4

Voici comment cela devrait être (et veuillez ne pas modifier le backend ... certainement pas ... si votre pile avant ne prend pas en charge application/x-www-form-urlencoded, alors jetez-le ... avec un peu de chance, AngularJS le fait!

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: 'username='+$scope.username+'&password='+$scope.password
 }).then(function(response) {
    // on success
 }, function(response) {
    // on error
 });

Fonctionne comme un charme avec AngularJS 1.5

Les gens, laissez-vous donner quelques conseils:

  • Utilisez des promesses .then(success, error)lorsque vous traitez $http, oubliez .sucesset .errorrappelez (car ils sont dépréciés)

  • Sur le site angularjs ici " Vous ne pouvez plus utiliser la chaîne JSON_CALLBACK comme espace réservé pour spécifier où la valeur du paramètre de rappel doit aller. "

Si votre modèle de données est plus complexe que juste un nom d'utilisateur et un mot de passe, vous pouvez toujours le faire (comme suggéré ci-dessus)

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: json_formatted_data,
     transformRequest: function(data, headers) {
          return transform_json_to_urlcoded(data); // iterate over fields and chain key=value separated with &, using encodeURIComponent javascript function
     }
}).then(function(response) {
  // on succes
}, function(response) {
  // on error
});

Le document pour le encodeURIComponentpeut être trouvé ici

Mahieddine M. Ichir
la source
3

S'il s'agit d'un formulaire, essayez de remplacer l'en-tête par:

headers[ "Content-type" ] = "application/x-www-form-urlencoded; charset=utf-8";

et si ce n'est pas un formulaire et un simple json alors essayez cet en-tête:

headers[ "Content-type" ] = "application/json";
V31
la source
Ne rien recevoir. J'ai toujours reçu un $_POSTtableau vierge .!
Veer Shrivastav
cet appel $ http est-il dans votre contrôleur?
V31
une autre chose est votre php de fin de serveur?
V31
J'ai trouvé une solution pour le même problème pour @Veer?
V31
2
$http({

    method: "POST",
    url: "/server.php",
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    data: "name='Олег'&age='28'",


}).success(function(data, status) {
    console.log(data);
    console.log(status);
});
user8483090
la source
4
Les réponses codées uniquement ne sont pas utiles à la communauté. Veuillez consulter Comment répondre
abpatil
1

À partir des documents $ http, cela devrait fonctionner.

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Srinath
la source
@Kevin, je ne suis pas sûr de cela, mais ... une fois que j'ai essayé d'envoyer une chaîne, cela m'a montré une erreur
Srinath
@KevinB Fine..I got it..i pense que les en-têtes doivent être modifiés lors de l'envoi d'une chaîne .. stackoverflow.com/a/20276775/2466168
Srinath
1
Notez que l'envoi du bon headersn'affectera pas celui dataqui devra encore être encodé en url, d'une manière ou d'une autre.
Boaz
les données sont toujours envoyées dans json, vous devez encoder les données en x-www-form-urlencoded simplement ajouter un en-tête ne suffit pas
wendellmva
1

vous devez publier un simple objet javascript, rien d'autre

           var request = $http({
                method: "post",
                url: "process.cfm",
                transformRequest: transformRequestAsFormPost,
                data: { id: 4, name: "Kim" }
            });

            request.success(
                function( data ) {
                    $scope.localData = data;
                }
            );

si vous avez php comme back-end, vous devrez effectuer quelques modifications supplémentaires. consultez ce lien pour corriger le côté serveur php

harishr
la source
ce n'est PAS exactement ce qu'il a demandé, il a spécifiquement demandé comment les obtenir en tant que x-www-form-urlencoded, car il rencontre des problèmes avec les choses json publiées.
ppetermann
@ppetermann avez-vous vérifié l'historique des modifications de la question avant de voter.
harishr
1

Bien qu'une réponse tardive, j'ai trouvé que UrlSearchParams angulaire fonctionnait très bien pour moi, il prend également en charge le codage des paramètres.

let params = new URLSearchParams();
params.set("abc", "def");

let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded'});
let options = new RequestOptions({ headers: headers, withCredentials: true });
this.http
.post(UrlUtil.getOptionSubmitUrl(parentSubcatId), params, options)
.catch();
vanval
la source
0

Cela a fonctionné pour moi. J'utilise angular pour le front-end et laravel php pour le back-end. Dans mon projet, le web angulaire envoie des données json au back-end de laravel.

Ceci est mon contrôleur angulaire.

var angularJsApp= angular.module('angularJsApp',[]);
angularJsApp.controller('MainCtrl', function ($scope ,$http) {

    $scope.userName ="Victoria";
    $scope.password ="password"


       $http({
            method :'POST',
            url:'http://api.mywebsite.com.localhost/httpTest?callback=JSON_CALLBACK',
            data: { username :  $scope.userName , password: $scope.password},
            headers: {'Content-Type': 'application/json'}
        }).success(function (data, status, headers, config) {
            console.log('status',status);
            console.log('data',status);
            console.log('headers',status);
        });

});

Ceci est mon contrôleur laravel php back-end.

public function httpTest(){
        if (Input::has('username')) {
            $user =Input::all();
            return  Response::json($user)->setCallback(Input::get('callback'));
        }
    }

Ceci est mon routage laravel

Route::post('httpTest','HttpTestController@httpTest');

Le résultat dans le navigateur est


données d' état 200 JSON_CALLBACK ({"username": "Victoria", "password": "password", "callback": "JSON_CALLBACK"}); httpTesting.js: fonction 18 en-têtes (c) {a || (a = sc (b)); retourne c? a [K (c)] || null: a}

Il existe une extension chrome appelée postman. Vous pouvez utiliser pour tester votre URL principale, qu'elle fonctionne ou non. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

j'espère que ma réponse vous aidera.

meazuri
la source