¿Cómo puedo publicar datos como datos de formulario en lugar de una carga de solicitud?

En el siguiente código, el método AngularJS $http llama a la URL y envía el objeto xsrf como “Solicitud de carga útil” (como se describe en la pestaña de la red del depurador de Chrome). El método jQuery $.ajax realiza la misma llamada, pero envía xsrf como “Datos de formulario”.

¿Cómo puedo hacer que AngularJS envíe xsrf como datos de formulario en lugar de una carga de solicitud?

 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 siguiente línea debe agregarse al objeto $ http que se pasa:

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

Y los datos pasados ​​deben convertirse a una cadena codificada en URL:

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

Entonces tienes algo como:

 $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_72EZcDsJ

ACTUALIZAR

Para usar los nuevos servicios agregados con AngularJS V1.4, consulte

  • Variables de encoding URL que utilizan solo servicios AngularJS

Si no desea usar jQuery en la solución, puede intentarlo. Solución atrapada desde aquí 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 confusión en torno a este tema me inspiró a escribir una publicación en un blog sobre el tema. La solución que propongo en esta publicación es mejor que su solución actual mejor valorada porque no lo limita a parametrizar su objeto de datos para llamadas de servicio $ http; es decir, con mi solución simplemente puede continuar pasando objetos de datos reales a $ http.post (), etc. y aun así lograr el resultado deseado.

Además, la respuesta mejor clasificada se basa en la inclusión de jQuery completo en la página para la función $ .param (), mientras que mi solución es jQuery agnostic, pura AngularJS ready.

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

Espero que esto ayude.

Tomé algunas de las otras respuestas e hice algo un poco más limpio, coloque esta llamada .config() al final de su angular.module en su 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 partir de AngularJS v1.4.0, hay un servicio $httpParamSerializer que convierte cualquier objeto en una parte de una solicitud HTTP de acuerdo con las reglas que se enumeran en la página de documentos .

Se puede usar así:

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

Recuerde que para una publicación correcta del formulario, el encabezado Content-Type debe ser cambiado. Para hacer esto globalmente para todas las solicitudes POST, se puede usar este código (tomado de la mitad de respuesta de Albireo):

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

Para hacer esto solo para la publicación actual, la propiedad de headers del objeto de solicitud debe modificarse:

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

Puedes definir el comportamiento globalmente:

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

De modo que no tiene que redefinirlo cada vez:

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

Como solución alternativa, puede hacer que el código que recibe el mensaje POST responda a los datos de la aplicación / json. Para PHP agregué el código a continuación, lo que me permite POSTAR en forma codificada 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 

Estas respuestas parecen una locura exagerada, a veces, lo simple es simplemente mejor:

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

Puedes probar con la siguiente solución

 $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 servicio de adaptador para la publicación:

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

Úselo en sus controladores o lo que sea:

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

Hay un tutorial muy bueno que repasa esta y otras cosas relacionadas: Envío de formularios AJAX: The AngularJS Way .

Básicamente, debe configurar el encabezado de la solicitud POST para indicar que está enviando datos del formulario como una cadena codificada en la URL, y establecer que los datos se envíen con el mismo 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) }); 

Tenga en cuenta que la función auxiliar de jQuery param () se usa aquí para serializar los datos en una cadena, pero también puede hacerlo manualmente si no se usa jQuery.

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

¡Por favor consulte! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

Para usuarios de Symfony2:

Si no desea cambiar nada en su javascript para que esto funcione, puede hacer estas modificaciones en su aplicación Symfony:

Cree una clase que amplíe 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; } } 

Ahora usa tu clase en app_dev.php (o cualquier archivo de índice que uses)

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

Simplemente configurar el tipo de contenido no es suficiente, la URL codifica los datos del formulario antes del envío. $http.post(url, jQuery.param(data))

Actualmente estoy usando la siguiente solución que encontré en el grupo AngularJS google.

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

Tenga en cuenta que si está usando PHP, necesitará usar algo como Request::createFromGlobals() del componente HTTP de Symfony 2 para leer esto, ya que $ _POST no se cargará automáticamente.

AngularJS lo está haciendo bien, ya que está haciendo el siguiente tipo de contenido dentro del encabezado http-request:

 Content-Type: application/json 

Si va con php como yo, o incluso con Symfony2, simplemente puede extender su compatibilidad de servidor para el estándar json como se describe aquí: http://silex.sensiolabs.org/doc/cookbook/json_request_body.html

La forma Symfony2 (por ejemplo, dentro de su 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()); 

La ventaja sería que no necesita usar jQuery param y podría usar AngularJS como su forma nativa de hacer tales solicitudes.

Respuesta completa (desde angular 1.4). Necesita incluir la dependencia de $ 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) { }); 

En la configuración de tu aplicación

 $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 su solicitud de recursos:

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

Esta no es una respuesta directa, sino una dirección de diseño ligeramente diferente:

No publique los datos como un formulario, sino como un objeto JSON para asignarlos directamente al objeto del lado del servidor, o use la variable de ruta de estilo REST

Ahora sé que ninguna opción podría ser adecuada en su caso, ya que está tratando de pasar una clave XSRF. Asignarlo a una variable de ruta como esta es un diseño terrible:

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

Porque por naturaleza querrías pasar la clave xsrf a otra ruta también, /login , /book-appointment etc. y no querrás meter tu bonita URL

Curiosamente, agregarlo como un campo de objeto tampoco es apropiado, porque ahora en cada uno de los objetos json que pasas al servidor debes agregar el campo

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

Ciertamente no desea agregar otro campo en su clase del lado del servidor que no tenga una asociación semántica directa con el objeto de dominio.

En mi opinión, la mejor manera de pasar su clave xsrf es a través de un encabezado HTTP. Muchas de las protecciones de xsrf del servidor web de la biblioteca del framework lo soportan. Por ejemplo, en Java Spring, puede pasarlo usando el encabezado X-CSRF-TOKEN .

La excelente capacidad de Angular para unir el objeto JS al objeto UI significa que podemos deshacernos de la práctica de publicar formularios todos juntos, y publicar JSON en su lugar. JSON se puede deserializar fácilmente en objetos del lado del servidor y admite estructuras de datos complejas como mapas, matrices, objetos nesteds, etc.

¿Cómo se publica una matriz en una carga útil de formulario? Tal vez así:

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

o esto:

 shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday 

Ambos son diseños deficientes ..

Esto es lo que estoy haciendo para mi necesidad, donde necesito enviar los datos de inicio de sesión a la API como datos de formulario y el objeto Javascript (datos de usuario) se convierte automáticamente a datos codificados en la 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); }); 

Así es como mi Userdata es

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

Lo único delgado que tiene que cambiar es usar “parámetros” de propiedad en lugar de “datos” cuando crea su objeto $ http:

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

En el ejemplo anterior, los clientes [i] son ​​solo objetos JSON (no serializados de ninguna manera). Si usa “params” en lugar de “datos”, angular serializará el objeto por usted usando $ httpParamSerializer: https://docs.angularjs.org/api/ng/service/ $ httpParamSerializer

Use el servicio AngularJS $http y use su método de post o configure la función $http .