Como posso postar dados como dados de formulário em vez de uma carga útil de solicitação?

No código abaixo, o método AngularJS $http chama o URL e envia o object xsrf como “Solicitar Carga Útil” (conforme descrito na guia Rede do depurador do Chrome). O método jQuery $.ajax faz a mesma chamada, mas envia xsrf como “Dados de formulário”.

Como posso fazer com que o AngularJS envie xsrf como dados de formulário em vez de uma carga útil de solicitação?

 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 seguinte linha precisa ser adicionada ao object $ http que é passado:

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

E os dados transmitidos devem ser convertidos em uma string codificada por URL:

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

Então você tem 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

ATUALIZAR

Para usar novos serviços adicionados com o AngularJS V1.4, consulte

  • Variáveis ​​de codificação de URL usando apenas serviços AngularJS

Se você não quiser usar o jQuery na solução, tente isso. Solução nabbed daqui 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 () {}); 

A contínua confusão em torno desta questão me inspirou a escrever um post sobre isso. A solução que proponho neste post é melhor do que a sua solução atual, porque ela não restringe a parametrização do seu object de dados para chamadas de serviço $ http; ou seja, com a minha solução, você pode simplesmente continuar a passar objects de dados reais para $ http.post (), etc., e ainda alcançar o resultado desejado.

Além disso, a melhor resposta depende da inclusão de jQuery completo na página para a function $ .param (), enquanto minha solução é jQuery agnóstica, pura AngularJS pronta.

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

Espero que isto ajude.

Eu peguei algumas das outras respostas e fiz algo um pouco mais limpo, coloque essa chamada .config() no final do seu angular.module no seu 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 do AngularJS v1.4.0, há um serviço $httpParamSerializer que converte qualquer object em uma parte de uma solicitação HTTP de acordo com as regras listadas na página docs .

Pode ser usado assim:

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

Lembre-se de que, para uma postagem de formulário correta, o header Content-Type deve ser alterado. Para fazer isso globalmente para todas as solicitações POST, esse código (tirado da meia resposta do Albireo) pode ser usado:

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

Para fazer isso apenas para a postagem atual, a propriedade headers do object request precisa ser modificada:

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

Você pode definir o comportamento globalmente:

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

Então você não precisa redefinir isso toda vez:

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

Como solução alternativa, você pode simplesmente fazer com que o código que recebe o POST responda aos dados do aplicativo / json. Para o PHP, adicionei o código abaixo, permitindo-me enviar POST para ele em formato codificado ou 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 

Essas respostas parecem um exagero insano, às vezes, simples é melhor:

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

Você pode tentar com a solução abaixo

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

Crie um serviço de adaptador para postagem:

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

Use em seus controladores ou o que for:

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

Existe um tutorial muito legal sobre este e outros assuntos relacionados – Enviando Formulários AJAX: O Jeito AngularJS .

Basicamente, você precisa definir o header da solicitação POST para indicar que está enviando dados de formulário como uma string codificada de URL e definir os dados a serem enviados no mesmo 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) }); 

Observe que a function auxiliar param do (jQuery) é usada aqui para serializar os dados em uma string, mas você pode fazer isso manualmente também, se não estiver usando 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 verifique! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

Para usuários do Symfony2:

Se você não quer mudar nada no seu javascript para que isso funcione, você pode fazer essas modificações em seu aplicativo symfony:

Crie uma class que estenda a class Symfony \ Component \ HttpFoundation \ 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; } } 

Agora use você class em app_dev.php (ou qualquer arquivo de índice que você usa)

 // 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 definir Content-Type não é suficiente, codificar url dados do formulário antes de enviar. $http.post(url, jQuery.param(data))

Atualmente estou usando a seguinte solução que encontrei no grupo do Google AngularJS.

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

Note que se você estiver usando PHP, você precisará usar algo como Request::createFromGlobals() do componente HTTP do Symfony 2 para ler isto, pois $ _POST não será automaticamente carregado com ele.

O AngularJS está fazendo certo, fazendo o seguinte tipo de conteúdo dentro do header http-request:

 Content-Type: application/json 

Se você está indo com php como eu, ou mesmo com o Symfony2, você pode simplesmente estender sua compatibilidade de servidor para o padrão json como descrito aqui: http://silex.sensiolabs.org/doc/cookbook/json_request_body.html

O caminho do Symfony2 (por exemplo, dentro do seu 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()); 

A vantagem seria que você não precisa usar o parametro jQuery e você poderia usar o AngularJS como sua maneira original de fazer tais requisições.

Resposta completa (desde angular 1.4). Você precisa include de dependency $ 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) { }); 

Na sua configuração de aplicativo –

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

Com o seu pedido de recurso –

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

Esta não é uma resposta direta, mas sim uma direção de design ligeiramente diferente:

Não poste os dados como um formulário, mas como um object JSON a ser mapeado diretamente para o object do lado do servidor ou use a variável de caminho do estilo REST

Agora eu sei que nenhuma opção pode ser adequada no seu caso, já que você está tentando passar uma chave XSRF. Mapear isso em uma variável de caminho como essa é um design terrível:

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

Porque por natureza você gostaria de passar a chave xsrf para outro caminho também, /login , /book-appointment etc. e você não quer mexer no seu lindo URL

Curiosamente, adicioná-lo como um campo de object não é apropriado, porque agora em cada object json você passa para o servidor, você tem que adicionar o campo

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

Você certamente não deseja adicionar outro campo em sua class do lado do servidor que não tenha uma associação semântica direta com o object de domínio.

Na minha opinião, a melhor maneira de passar sua chave xsrf é através de um header HTTP. Muitas bibliotecas de frameworks web do lado do servidor de proteção xsrf suportam isso. Por exemplo, no Java Spring, você pode passá-lo usando o header X-CSRF-TOKEN .

A excelente capacidade do Angular de vincular o object JS ao object da interface do usuário significa que podemos nos livrar da prática de postar todos juntos e postar o JSON. O JSON pode ser facilmente desasseriado no object do lado do servidor e suportar estruturas de dados complexas, como mapa, matrizes, objects nesteds, etc.

Como você postar array em uma carga útil de formulário? Talvez assim:

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

ou isto:

 shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday 

Ambos são design pobre ..

Isto é o que eu estou fazendo para minha necessidade, onde eu preciso enviar os dados de login para API como dados de formulário e o object JavaScript (userData) está sendo convertido automaticamente para dados codificados de 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); }); 

É assim que meu Userdata é

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

A única coisa fina que você precisa mudar é usar propriedade “params” em vez de “data” quando você cria seu object $ http:

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

No exemplo acima, os clientes [i] são apenas objects JSON (não serializados de qualquer forma). Se você usar “params” em vez de “data”, o angular serializará o object para você usando $ httpParamSerializer: https://docs.angularjs.org/api/ng/service/ $ httpParamSerializer

Use o serviço AngularJS $http e use seu método post ou configure a function $http .