Come posso inviare dati come dati del modulo invece di un carico utile della richiesta?

Nel seguente codice, il metodo $http AngularJS $http chiama l’URL e invia l’object xsrf come “Request Payload” (come descritto nella scheda di rete del debugger di Chrome). Il metodo jQuery $.ajax esegue la stessa chiamata, ma invia xsrf come “Dati modulo”.

Come posso rendere AngularJS inviare xsrf come dati di modulo invece di un carico utile di richiesta?

 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() {} }); 

La seguente riga deve essere aggiunta all’object $ http passato:

 headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'} 

E i dati passati dovrebbero essere convertiti in una stringa con codifica URL:

 > $.param({fkey: "key"}) 'fkey=key' 

Quindi hai qualcosa come:

 $http({ method: 'POST', url: url, data: $.param({fkey: "key"}), headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'} }) 

Da: https://groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ

AGGIORNARE

Per utilizzare i nuovi servizi aggiunti con AngularJS V1.4, vedere

  • Variabili di codifica URL che utilizzano solo servizi AngularJS

Se non vuoi usare jQuery nella soluzione, puoi provare questo. Soluzione nascosta da qui 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 continua confusione che circonda questo problema mi ha spinto a scrivere un post sul blog. La soluzione che propongo in questo post è migliore della tua attuale soluzione più votata perché non ti limita a parametrizzare il tuo object dati per le chiamate al servizio $ http; cioè con la mia soluzione puoi semplicemente continuare a passare oggetti dati reali a $ http.post (), ecc. e comunque ottenere il risultato desiderato.

Inoltre, la risposta più votata si basa sull’inclusione di jQuery completo nella pagina per la funzione $ .param (), mentre la mia soluzione è jQuery agnostic, pura AngularJS ready.

http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

Spero che questo ti aiuti.

Ho preso alcune delle altre risposte e ho fatto qualcosa di un po ‘più pulito, metti questa chiamata .config() alla fine di angular.module nel tuo app.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("&"); }); }]); 

A partire da AngularJS v1.4.0, esiste un servizio $httpParamSerializer che converte qualsiasi object in una parte di una richiesta HTTP in base alle regole elencate nella pagina dei documenti .

Può essere usato in questo modo:

 $http.post('http://example.com', $httpParamSerializer(formDataObj)). success(function(data){/* response status 200-299 */}). error(function(data){/* response status 400-999 */}); 

Ricordare che per un post di modulo corretto, l’intestazione Content-Type deve essere modificata. Per fare questo globalmente per tutte le richieste POST, questo codice (tratto dalla mezza risposta di Albireo) può essere usato:

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

Per fare ciò solo per il post corrente, la proprietà delle headers dell’object richiesta deve essere modificata:

 var req = { method: 'POST', url: 'http://example.com', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: $httpParamSerializer(formDataObj) }; $http(req); 

Puoi definire il comportamento globalmente:

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

Quindi non devi ridefinirlo ogni volta:

 $http.post("/handle/post", { foo: "FOO", bar: "BAR" }).success(function (data, status, headers, config) { // TODO }).error(function (data, status, headers, config) { // TODO }); 

Per ovviare al problema, è sufficiente fare in modo che il codice che riceve il POST risponda ai dati dell’applicazione / JSON. Per PHP ho aggiunto il codice qui sotto, permettendomi di postare in esso sia in forma codificata o 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 

Queste risposte sembrano un pazzo eccessivo, a volte, semplice è solo meglio:

 $http.post(loginUrl, "userName=" + encodeURIComponent(email) + "&password=" + encodeURIComponent(password) + "&grant_type=password" ).success(function (data) { //... 

Puoi provare con la soluzione qui sotto

 $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 */ }); 

Crea un servizio adattatore per il post:

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

Usalo nei tuoi controller o qualsiasi altra cosa:

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

C’è un tutorial davvero bello che tratta questo e altri argomenti correlati – Invio di moduli AJAX: The AngularJS Way .

Fondamentalmente, è necessario impostare l’intestazione della richiesta POST per indicare che si inviano i dati del modulo come una stringa con codifica URL e impostare i dati per l’invio dello stesso formato

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

Nota che la funzione helper param () di jQuery è usata qui per serializzare i dati in una stringa, ma puoi farlo manualmente anche se non usi jQuery.

 var fd = new FormData(); fd.append('file', file); $http.post(uploadUrl, fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }) .success(function(){ }) .error(function(){ }); 

Si prega di checkout! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

Per gli utenti di Symfony2:

Se non vuoi modificare nulla nel tuo javascript affinché funzioni, puoi apportare queste modifiche nella tua app symfony:

Crea una class che estende la class Symfony \ Component \ HttpFoundation \ Request:

 < ?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; } } 

Ora usa la tua class in app_dev.php (o qualsiasi file di indice che usi)

 // 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); 

Basta impostare Content-Type non è sufficiente, url codifica i dati del modulo prima dell’invio. $http.post(url, jQuery.param(data))

Attualmente sto usando la seguente soluzione che ho trovato nel gruppo google di AngularJS.

 $ http
 .post ('/ echo / json /', 'json =' + encodeURIComponent (angular.toJson (data)), {
     intestazioni: {
         'Content-Type': 'application / x-www-form-urlencoded;  charset = UTF-8'
     }
 }). success (function (data) {
     $ scope.data = data;
 });

Nota che se stai usando PHP, dovrai usare qualcosa come Request::createFromGlobals() del componente HTTP di Symfony 2 per leggerlo, dato che $ _POST non verrà automaticamente caricato con esso.

AngularJS lo sta facendo nel momento in cui esegue il seguente tipo di contenuto all’interno dell’intestazione della richiesta http:

 Content-Type: application/json 

Se stai usando php come me, o anche con Symfony2 puoi semplicemente estendere la compatibilità del server per lo standard json come descritto qui: http://silex.sensiolabs.org/doc/cookbook/json_request_body.html

Il modo Symfony2 (ad es. All’interno del tuo 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()); 

Il vantaggio sarebbe che non hai bisogno di usare il parametro jQuery e potresti usare AngularJS come metodo nativo per fare tali richieste.

Risposta completa (dal momento angular 1.4). È necessario includere la dipendenza $ 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) { }); 

Nella tua app 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); }; 

Con la tua richiesta di risorse –

  headers: { 'Content-Type': 'application/x-www-form-urlencoded' } 

Questa non è una risposta diretta, ma piuttosto una direzione progettuale leggermente diversa:

Non pubblicare i dati come modulo, ma come object JSON da mappare direttamente sull’object lato server o utilizzare la variabile percorso stile REST

Ora so che nessuna delle due opzioni potrebbe essere adatta nel tuo caso poiché stai cercando di passare una chiave XSRF. Mapparlo in una variabile di percorso come questo è un disegno terribile:

 http://www.someexample.com/xsrf/{xsrfKey} 

Perché per natura vorresti passare la chiave xsrf anche ad altri percorsi, /login , /book-appointment ecc. E non vuoi rovinare il tuo bel URL

È interessante notare che aggiungerlo come campo object non è appropriato, perché ora su ciascun object JSON che si passa al server è necessario aggiungere il campo

 { appointmentId : 23, name : 'Joe Citizen', xsrf : '...' } 

Certamente non vuoi aggiungere un altro campo sulla tua class lato server che non ha un’associazione semantica diretta con l’object dominio.

Secondo me il modo migliore per passare la tua chiave xsrf è tramite un’intestazione HTTP. Questa libreria di web framework sul lato server di protezione xsrf supporta questo. Ad esempio in Java Spring, è ansible passarlo utilizzando l’intestazione X-CSRF-TOKEN .

L’eccellente capacità di Angular di bind l’object JS all’object UI significa che possiamo sbarazzarci della pratica del modulo di post tutti insieme e postare invece JSON. JSON può essere facilmente serializzabile nell’object lato server e supporta strutture dati complesse come mappe, matrici, oggetti nidificati, ecc.

Come pubblichi un array in un payload del modulo? Forse così:

 shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday 

o questo:

 shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday 

Entrambi sono di design scadente ..

Questo è ciò che sto facendo per il mio bisogno, dove devo inviare i dati di accesso all’API come dati del modulo e l’object Javascript (userData) viene convertito automaticamente in dati codificati 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); }); 

Questo è il mio Userdata

 var userData = { grant_type: 'password', username: loginData.userName, password: loginData.password } 

L’unico limite che devi modificare è utilizzare “parametri” di proprietà anziché “dati” quando crei il tuo object $ http:

 $http({ method: 'POST', url: serviceUrl + '/ClientUpdate', params: { LangUserId: userId, clientJSON: clients[i] }, }) 

Nell’esempio sopra i client [i] sono solo oggetti JSON (non serializzati in alcun modo). Se usi “params” piuttosto che “data” angular serializzerà l’object per te usando $ httpParamSerializer: https://docs.angularjs.org/api/ng/service/ $ httpParamSerializer

Utilizzare il servizio $http AngularJS $http e utilizzare il suo metodo post o configurare la funzione $http .