ajax - validacion - validar formulario jquery antes de enviar
¿Cómo puedo publicar datos como datos de formulario en lugar de una carga útil de solicitud? (22)
En el código a continuación, el método AngularJS $http
llama a la URL y envía el objeto xsrf como una "Carga útil de solicitud" (como se describe en la pestaña de la red del depurador Chrome). El método jQuery $.ajax
hace 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 útil 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() {}
});
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 de formulario correcta, se debe cambiar el encabezado Content-Type
. Para hacer esto globalmente para todas las solicitudes POST, este código (tomado de la media respuesta de Albireo) se puede usar:
$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);
Actualmente estoy usando la siguiente solución que found en el grupo de 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; });
Tenga en cuenta que si está usando PHP, necesitará usar algo como la Request::createFromGlobals()
del componente HTTP de Symfony 2 Request::createFromGlobals()
para leer esto, ya que $ _POST no se cargará automáticamente con él.
AngularJS lo está haciendo bien al hacer el siguiente tipo de contenido dentro del encabezado de solicitud http:
Content-Type: application/json
Si va con php como yo, o incluso con Symfony2, simplemente puede ampliar la compatibilidad de su 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 tu 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 su forma nativa de hacer tales solicitudes.
Como solución alternativa, simplemente puede hacer que el código que recibe el POST responda a los datos de la aplicación / json. Para PHP, agregué el siguiente código, permitiéndome POST en formato JSON o codificado.
//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
Crear 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''}
})
}
})
Úsalo en tus 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)
})
}
})
En la configuración de su 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 que se asignará directamente al objeto del lado del servidor, o use la variable de ruta de estilo REST
Ahora sé que ninguna de las opciones podría ser adecuada en su caso, ya que está intentando pasar una clave XSRF. Mapearlo en una variable de ruta como esta es un diseño terrible:
http://www.someexample.com/xsrf/{xsrfKey}
Porque por naturaleza, también querría pasar la clave xsrf a otra ruta, /login
, /book-appointment
etc. y no quiere desordenar su bonita URL.
Interesantemente, agregarlo como un campo de objeto tampoco es apropiado, porque ahora en cada uno de los objetos json que pasa al servidor tiene que 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 bibliotecas de marco web del lado del servidor de protección xsrf admiten esto Por ejemplo, en Java Spring, puede pasarlo usando el encabezado X-CSRF-TOKEN
.
La excelente capacidad de Angular para vincular el objeto JS al objeto UI significa que podemos deshacernos de la práctica de publicar el formulario todos juntos y, en su lugar, publicar JSON. JSON puede ser fácilmente serializado en objetos del lado del servidor y soportar estructuras de datos complejas como mapas, matrices, objetos anidados, etc.
¿Cómo se publica la 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 de diseño pobre ..
Estas respuestas parecen una exageración insana, a veces, simple es simplemente mejor:
$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
"&password=" + encodeURIComponent(password) +
"&grant_type=password"
).success(function (data) {
//...
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 (userData) se convierte automáticamente a datos codificados en 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
}
Hay un tutorial realmente bueno que repasa esto 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 de formulario como una cadena codificada de URL y configurar los datos para que se envíen en 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 de ayuda param () de jQuery se usa aquí para serializar los datos en una cadena, pero puede hacerlo manualmente también si no usa jQuery.
La continua confusión en torno a este tema me inspiró a escribir una publicación de blog al respecto. La solución que propongo en esta publicación es mejor que su mejor solución actual, ya que no le restringe la parametrización de su objeto de datos para llamadas de servicio de $ http; es decir, con mi solución, simplemente puede continuar pasando los objetos de datos reales a $ http.post (), etc. y aún así lograr el resultado deseado.
Además, la respuesta más valorada 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 agnóstica, lista para AngularJS puro.
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
Espero que esto ayude.
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 en una cadena codificada en URL:
> $.param({fkey: "key"})
''fkey=key''
Así que tienes algo como:
$http({
method: ''POST'',
url: url,
data: $.param({fkey: "key"}),
headers: {''Content-Type'': ''application/x-www-form-urlencoded; charset=UTF-8''}
})
Desde: https://groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ
ACTUALIZAR
Para usar los nuevos servicios agregados con AngularJS V1.4, vea
- Variables de codificación de URL que utilizan solo servicios de AngularJS
Lo único que tienes que cambiar es usar la propiedad "params" en lugar de "datos" cuando crees tu 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 "parámetros" en lugar de "datos", el objeto serializará el objeto usando $ httpParamSerializer: https://docs.angularjs.org/api/ng/service/ $ httpParamSerializer
Para usuarios de Symfony2:
Si no quieres cambiar nada en tu javascript para que esto funcione, puedes hacer estas modificaciones en tu aplicación de Symfony:
Crea una clase que amplíe la clase 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;
}
}
Ahora use su clase en app_dev.php (o cualquier archivo de índice que use)
// 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);
Puedes definir el comportamiento globalmente:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
Así que no tienes que redefinir cada vez que:
$http.post("/handle/post", {
foo: "FOO",
bar: "BAR"
}).success(function (data, status, headers, config) {
// TODO
}).error(function (data, status, headers, config) {
// TODO
});
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 */
});
Respuesta completa (desde angular 1.4). Debe incluir la dependencia $ 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) {
});
Si no desea utilizar jQuery en la solución, puede intentar esto. Solución atrapada desde aquí https://.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 () {});
Simplemente configurar Contenido-Tipo no es suficiente, url codificar datos de formulario antes de enviar. $http.post(url, jQuery.param(data))
Tomé algunas de las otras respuestas e hice algo un poco más limpio, puse esta llamada .config()
al final de angular.module en tu 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("&");
});
}]);
Use el servicio AngularJS $http
y use su método de post
o configure la función $http
.
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