Como POSTAR os dados do formulário codificado em url com $ http sem jQuery?

195

Eu sou novo no AngularJS e, para começar, pensei em desenvolver um novo aplicativo usando apenas o AngularJS.

Estou tentando fazer uma chamada AJAX para o lado do servidor, usando $httpmeu aplicativo Angular.

Para enviar os parâmetros, tentei o seguinte:

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

Isso está funcionando, mas também está usando o jQuery $.param. Para remover a dependência do jQuery, tentei:

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

mas isso pareceu falhar. Então eu tentei params:

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

mas isso também pareceu falhar. Então eu tentei JSON.stringify:

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

Encontrei essas respostas possíveis para minha busca, mas não obtive êxito. Estou fazendo algo errado? Tenho certeza de que o AngularJS forneceria essa funcionalidade, mas como?

Veer Shrivastav
fonte
Eu não sei qual é o problema real, mas você tentou isso #$http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});
Mritunjay
1
Seu primeiro método deve funcionar, está $scope.userNamedefinido? por que você não tentou data: data?
Kevin B
@ KevinB: desculpe .. Eu fiz a edição correta.
Veer Shrivastav
@mritunjay: desculpe .. eu fiz a edição .. eu estava tentando o mesmo.
Veer Shrivastav
@ Vere funcionou ou você ainda está tendo problemas?
V31

Respostas:

409

Eu acho que você precisa fazer é transformar seus dados de objeto não em JSON, mas em parâmetros de URL.

Do blog de Ben Nadel .

Por padrão, o serviço $ http transformará a solicitação de saída serializando os dados como JSON e depois publicando-os com o tipo de conteúdo "application / json". Quando queremos postar o valor como uma postagem de FORM, precisamos alterar o algoritmo de serialização e publicar os dados com o tipo de conteúdo "application / x-www-form-urlencoded".

Exemplo daqui .

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

ATUALIZAR

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

allenhwkim
fonte
41
Obrigado por não usar o JQuery!
Overmars
1
e se eu precisar enviar dados de várias partes / formulário?
Dejell
2
Contanto que o angular incorpore o jqLite abaixo angular.element, você pode simplesmentereturn angular.element.param(obj);
Vicary
4
@Vicary Lembre-se de que param () não é implementado no jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.element
Alex Pavlov
1
este é outro caminho a percorrer var obj = {a: 1, b: 2}; Object.keys(obj).reduce(function(p, c) { return p.concat([encodeURIComponent(c) + "=" + encodeURIComponent(obj[c])]); }, []).join('&');
test30
136

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

Com o AngularJS 1.4 e superior, dois serviços podem lidar com o processo de codificação de dados de URL para solicitações POST, eliminando a necessidade de manipular os dados com transformRequestou usando dependências externas como o jQuery:

  1. $httpParamSerializerJQLike- um serializador inspirado no jQuery .param()( recomendado )

  2. $httpParamSerializer - um serializador usado pelo próprio Angular para solicitações GET

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

Veja uma demonstração mais detalhada do Plunker


Como são $httpParamSerializerJQLikee $httpParamSerializerdiferentes

Em geral, parece $httpParamSerializerusar menos formato de codificação de URL "tradicional" do que $httpParamSerializerJQLikequando se trata de estruturas de dados complexas.

Por exemplo (ignorando a porcentagem de codificação de colchetes):

Codificando uma matriz

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

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

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

Codificando um 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
Boaz
fonte
Como podemos usar isso em $ resource dentro de uma fábrica?
stilllife
2
Deve ser em $http.({...vez de`$http.post({...
Carlos Granados
@CarlosGranados Obrigado por perceber. Corrigido esse erro de digitação aqui e na demonstração do Plunker.
Boaz
Isso funcionou perfeitamente após a migração de jQuery para AngularJS
zero298
4
Esta é a resposta específica do AngularJS que eu estava procurando. Eu gostaria que o pôster selecionasse isso como a melhor resposta.
Marty Chang
61

Tudo isso parece um exagero (ou não funciona) ... basta fazer o seguinte:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Serj Sagan
fonte
11
Finalmente algum senso comum
jlewkovich
Isso não enviará a solicitação com o cabeçalho do tipo de conteúdo errado?
22416 Phil
Funcionou para mim ... não sei qual era o cabeçalho, mas a solicitação funcionou e permitiu a autenticação com êxito. Por que você não testá-lo e nos informar.
Serj Sagan
5
@ Philip Acho que pode depender do servidor, recebi uma solicitação ruim, até que eu adicionei {headers: {'Content-Type': 'application / x-www-form-urlencoded'}} como o argumento de configuração ou uso de fornecimento o construtor $ http (config) como a resposta dos moices mostra. De qualquer forma, isso é superior à resposta aceita, pois não introduz alguma transformação mágica e não requer o usuário de algum serviço auxiliar. Obrigado!
Sr. Bungle
23

O problema é o formato de sequência JSON. É possível usar uma sequência de URL simples nos dados:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
moices
fonte
7
você tem que usar encodeURIComponent($scope.userName)a url codificar os dados ou seus parâmetros vão ser corrompidos se o usuário entra valor como"&myCustomParam=1"
Ivan Hušnjak
2
esta é a única resposta que funcionou para mim! Eu saltei sucesso, mas $ http formato é bom
xenteros
4

Aqui está como deve ser (e por favor, sem alterações no back-end ... certamente não ... se sua pilha da frente não suportar application/x-www-form-urlencoded, jogue-a fora ... espero que o AngularJS faça!

$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 um encanto com o AngularJS 1.5

Gente, vamos dar alguns conselhos:

  • use promessas .then(success, error)ao lidar com $http, esquecer .sucesse .errorretornos de chamada (como estão sendo preteridos)

  • No site angularjs, aqui " Você não pode mais usar a string JSON_CALLBACK como um espaço reservado para especificar para onde deve ir o valor do parâmetro de retorno de chamada. "

Se o seu modelo de dados for mais complexo que apenas um nome de usuário e uma senha, você ainda poderá fazer isso (como sugerido acima)

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

O documento para o encodeURIComponentpode ser encontrado aqui

Mahieddine M. Ichir
fonte
3

Se for um formulário, tente alterar o cabeçalho para:

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

e se não for um formulário e um json simples, tente este cabeçalho:

headers[ "Content-type" ] = "application/json";
V31
fonte
Não estou recebendo nada. Eu ainda recebi uma $_POSTmatriz em branco .!
Veer Shrivastav
esta chamada $ http no seu controlador?
V31 25/07
mais uma coisa é o seu servidor final php?
V31 25/07
Eu encontrei uma solução para o mesmo, você ainda está tendo o problema @Veer?
V31 29/07
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);
});
user8483090
fonte
4
Respostas apenas de código não são úteis para a comunidade. Veja como responder
abpatil
1

Nos documentos $ http, isso deve funcionar.

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Srinath
fonte
@ Kevin não estou certo sobre este but..once quando eu tentei enviar uma corda que me mostrou um erro
Srinath
@KevinB Fine..I tem it..i acho cabeçalhos são necessários para ser alterado durante o envio de uma corda .. stackoverflow.com/a/20276775/2466168
Srinath
1
Observe que o envio do correto headersnão afetaria o dataque ainda precisará ser codificado em url, de uma maneira ou de outra.
Boaz
dados ainda são enviados em JSON você deve codificar os dados em x-www-form-urlencoded apenas adicionando um cabeçalho não é suficiente
wendellmva
1

você precisa postar objeto javascript simples, nada mais

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

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

se você tiver o php como back-end, precisará fazer mais algumas modificações. confira este link para corrigir o lado do servidor php

harishr
fonte
isso NÃO é exatamente o que ele pediu, ele perguntou especificamente como ele pode obtê-los como x-www-form-urlencoded, porque ele está tendo problemas com as coisas de json postadas.
ppetermann
@ppetermann você tem verificado o histórico de edição da pergunta antes downvoting ..
harishr
1

Embora seja uma resposta tardia, achei que o UrlSearchParams angular funcionou muito bem para mim, mas também cuida da codificação 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
fonte
0

Isso funcionou para mim. Eu uso angular para front-end e laravel php para back-end. No meu projeto, a web angular envia dados json para o back-end do laravel.

Este é o meu 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 é o meu controlador laravel de back-end php.

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

Este é o meu roteamento laravel

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

O resultado no navegador é


dados do status 200 JSON_CALLBACK ({"nome de usuário": "Victoria", "senha": "senha", "retorno de chamada": "JSON_CALLBACK"}); httpTesting.js: função de 18 cabeçalhos (c) {a || (a = sc (b)); retorno c? a [K (c)] || null: a}

Existe uma extensão do chrome chamada carteiro. Você pode usar para testar seu URL de back-end, se está funcionando ou não. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

espero que minha resposta o ajude.

meazuri
fonte