¿Cómo PUEDO PUBLICAR datos de formulario urlencoded con $ http sin jQuery?

195

Soy nuevo en AngularJS y, para empezar, pensé en desarrollar una nueva aplicación utilizando solo AngularJS.

Estoy tratando de hacer una llamada AJAX al lado del servidor, usando $httpdesde mi aplicación angular.

Para enviar los parámetros, probé lo siguiente:

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

Esto está funcionando, pero también está usando jQuery en $.param. Para eliminar la dependencia de jQuery, probé:

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

pero esto pareció fallar. Entonces intenté params:

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

pero esto también pareció fallar. Entonces intenté JSON.stringify:

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

Encontré estas posibles respuestas a mi búsqueda, pero no tuve éxito. ¿Estoy haciendo algo mal? Estoy seguro de que AngularJS proporcionaría esta funcionalidad, pero ¿cómo?

Veer Shrivastav
fuente
No sé cuál es el problema real, pero ¿intentaste esto$http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});
Mritunjay
1
Su primer método debería funcionar, ¿está $scope.userNamedefinido? ¿Por qué no lo intentaste data: data?
Kevin B
@KevinB: lo siento ... hice la edición correcta.
Veer Shrivastav
@mritunjay: lo siento ... hice la edición ... estaba intentando lo mismo.
Veer Shrivastav
@Veer ¿funcionó o aún tienes problemas?
V31

Respuestas:

409

Creo que lo que debe hacer es transformar sus datos del objeto no en una cadena JSON, sino en url params.

Del blog de Ben Nadel .

De manera predeterminada, el servicio $ http transformará la solicitud saliente al serializar los datos como JSON y luego publicarlos con el tipo de contenido, "aplicación / json". Cuando deseamos publicar el valor como una publicación FORM, necesitamos cambiar el algoritmo de serialización y publicar los datos con el tipo de contenido, "application / x-www-form-urlencoded".

Ejemplo de aquí .

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

ACTUALIZAR

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

allenhwkim
fuente
41
¡Gracias por no usar JQuery!
OverMars
1
¿Qué sucede si necesito enviar datos multiparte / formulario?
Dejell el
2
Mientras angular incruste jqLite debajo angular.element, puede simplementereturn angular.element.param(obj);
Vicary
44
Mantenga en mente que @Vicary parámetro () no está implementado en jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.element
Alex Pavlov
1
esta es otra forma de hacerlo 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 codificación de URL utilizando solo servicios AngularJS

Con AngularJS 1.4 y versiones posteriores, dos servicios pueden manejar el proceso de codificación de datos url para solicitudes POST, eliminando la necesidad de manipular los datos con transformRequesto usando dependencias externas como jQuery:

  1. $httpParamSerializerJQLike- un serializador inspirado en jQuery's .param()( recomendado )

  2. $httpParamSerializer - un serializador utilizado por Angular para solicitudes GET

Ejemplo de uso

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

Vea una demostración más detallada de Plunker


Como son $httpParamSerializerJQLikey $httpParamSerializerdiferentes

En general, parece que $httpParamSerializerutiliza un formato de codificación de URL menos "tradicional" que $httpParamSerializerJQLikecuando se trata de estructuras de datos complejas.

Por ejemplo (ignorando el porcentaje de codificación de paréntesis):

Codificar una matriz

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

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

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

Codificar un objeto

{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
Booz
fuente
¿Cómo podemos usar esto en $ resource dentro de una fábrica?
stilllife
2
Debería ser en $http.({...lugar de`$http.post({...
Carlos Granados
@CarlosGranados Gracias por notarlo. Corregido este error tipográfico aquí y en la demostración de Plunker.
Boaz el
Esto funcionó perfectamente después de migrar de jQuery a AngularJS
zero298
44
Esta es la respuesta específica de AngularJS que estaba buscando. Desearía que el póster seleccione esto como la mejor respuesta.
Marty Chang
61

Todo esto parece excesivo (o no funciona) ... solo haz esto:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Serj Sagan
fuente
11
Finalmente algo de sentido común
jlewkovich
¿No enviará esto la solicitud con el encabezado de tipo de contenido incorrecto?
Phil
Funcionó para mí ... no estoy seguro de cuál era el encabezado, pero la solicitud funcionó y permitió autenticar con éxito. ¿Por qué no lo prueba y nos lo hace saber?
Serj Sagan
55
@ Phil Supongo que puede depender del servidor, recibí una solicitud incorrecta, hasta que agregué {encabezados: {'Content-Type': 'application / x-www-form-urlencoded'}} como el argumento de configuración, o uso de suministro el constructor $ http (config) como muestra la respuesta de moices. De cualquier manera, esto es superior a la respuesta aceptada, ya que no introduce alguna transformación mágica y no requiere el usuario de algún servicio auxiliar. ¡Gracias!
Sr. Bungle
23

El problema es el formato de cadena JSON. Puede usar una cadena URL simple en los datos:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
moices
fuente
77
debe usar encodeURIComponent($scope.userName)para codificar los datos de la URL o sus parámetros se corromperán si el usuario ingresa un valor como"&myCustomParam=1"
Ivan Hušnjak
2
¡Esta es la única respuesta que me ha funcionado! Me salteé el éxito, pero el formato $ http es bueno
xenteros
4

Esta es la forma en que debería ser (y, por favor, no haya cambios en el backend ... ciertamente no ... si su stack frontal no es compatible application/x-www-form-urlencoded, tírelo ... ¡con suerte AngularJS sí lo hace!

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

Funciona como un encanto con AngularJS 1.5

Gente, déjenles un consejo:

  • use promesas .then(success, error)al tratar $http, olvídese .sucessy .errordevoluciones de llamada (ya que están en desuso)

  • Desde el sitio angularjs aquí " Ya no puede usar la cadena JSON_CALLBACK como marcador de posición para especificar dónde debe ir el valor del parámetro de devolución de llamada " .

Si su modelo de datos es más complejo que solo un nombre de usuario y una contraseña, aún puede hacerlo (como se sugirió anteriormente)

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

El documento para el encodeURIComponentse puede encontrar aquí

Mahieddine M. Ichir
fuente
3

Si es un formulario, intente cambiar el encabezado a:

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

y si no es un formulario y un json simple, intente este encabezado:

headers[ "Content-type" ] = "application/json";
V31
fuente
No recibo nada. Todavía recibí una $_POSTmatriz en blanco .
Veer Shrivastav
¿Es esta llamada $ http en su controlador?
V31
Una cosa más es su servidor PHP final?
V31
He encontrado una solución para lo mismo, ¿sigues teniendo el problema @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);
});
usuario8483090
fuente
44
Las respuestas de solo código no son útiles para la comunidad. Por favor, mire cómo responder
abpatil
1

Desde los documentos $ http esto debería funcionar ...

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Srinath
fuente
@Kevin, no estoy seguro de esto, pero ... una vez que intenté enviar una cadena me mostró un error
Srinath
@KevinB Bien ... Lo tengo ... creo que es necesario cambiar los encabezados mientras se envía una cadena ... stackoverflow.com/a/20276775/2466168
Srinath
1
Tenga en cuenta que el envío de la correcta headersno afectaría a la dataque aún deberá ser codificada de una manera u otra.
Boaz
los datos aún se envían en json, debe codificar los datos en x-www-form-urlencoded simplemente agregar un encabezado no es suficiente
wendellmva
1

necesita publicar un objeto javascript simple, nada más

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

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

si tiene php como back-end, entonces tendrá que hacer algunas modificaciones más ... consulte este enlace para arreglar el lado del servidor php

harishr
fuente
eso NO es exactamente lo que pidió, específicamente preguntó cómo puede obtenerlos como x-www-form-urlencoded, porque se encuentra con problemas con las publicaciones de json.
ppetermann
@ppetermann ¿Ha revisado el historial de edición de la pregunta antes de downvoting ..
harishr
1

Aunque fue una respuesta tardía, encontré que UrlSearchParams angular funcionó muy bien para mí, también se encarga de la codificación de parámetros.

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
fuente
0

Esto funcionó para mí. Uso angular para front-end y laravel php para back-end. En mi proyecto, la web angular envía datos json a laravel back-end.

Este es mi controlador angular.

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

});

Este es mi controlador laravel de back-end php.

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

Esta es mi ruta laravel

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

El resultado en el navegador es

estado 200
datos JSON_CALLBACK ({"nombre de usuario": "Victoria", "contraseña": "contraseña", "devolución de llamada": "JSON_CALLBACK"}); httpTesting.js: 18 encabezados función (c) {a || (a = sc (b)); devuelve c? a [K (c)] || nulo: a}

Hay una extensión de cromo llamada cartero. Puede usar para probar su URL de back-end si funciona o no. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

con suerte, mi respuesta te ayudará.

meazuri
fuente