Angular2 - Parâmetros de solicitação Http POST

91

Estou tentando fazer uma solicitação POST, mas não consigo fazer isso funcionar:

testRequest() {
      var body = 'username=myusername?password=mypassword';
      var headers = new Headers();
      headers.append('Content-Type', 'application/x-www-form-urlencoded');

      this.http
        .post('/api',
          body, {
            headers: headers
          })
          .subscribe(data => {
                alert('ok');
          }, error => {
              console.log(JSON.stringify(error.json()));
          });
}

Basicamente, quero replicar essa solicitação http (não ajax) como se fosse originada por um formulário html:

URL: / api

Params: nome de usuário e senha

Christopher
fonte
dê uma olhada em stackoverflow.com/a/34758630/5043867 e stackoverflow.com/a/34823818/5043867 que explicará tudo sobre a solicitação POST em detalhes!
Pardeep Jain
@PardeepJain não estou tentando consumir uma API. Apenas para simular um POST originado por um formulário html.
Christopher
também verifique aqui, poste um arquivo com user_namee password, stackoverflow.com/a/45879409/2803344
Belter

Respostas:

49

Acho que o corpo não é correto para um application/x-www-form-urlencodedtipo de conteúdo. Você pode tentar usar isto:

var body = 'username=myusername&password=mypassword';

Espero que ajude você, Thierry

Thierry Templier
fonte
sim, com esse tipo de conteúdo no cabeçalho, é a única solução passando valores "à moda antiga" em vez de string json
Nather Webber
Esta não é uma boa resposta. Use URLSearchParams em vez disso, como mencionado abaixo com mais votos positivos.
Mick
Para as pessoas do futuro que vêm de uma pesquisa no Google, esta não é a melhor resposta (sem ofensa Thierry! Sua resposta ainda está tecnicamente correta :)). A resposta de V Stoykov é até agora a mais precisa. ps certifique-se de import { URLSearchParams } from "@angular/http"e não o padrão, então 1) você não precisa fazer o .toStringnele, e 2) você não precisa definir o tipo de conteúdo. O Angular inferirá isso automaticamente para você (consulte github.com/angular/angular/blob/4.4.4/packages/http/src/… )
Eran Medan,
Oi ! se eu quiser passar o serviço de postagem com cabeçalho -> tipo de conteúdo como 'application / json' o que eu preciso passar no corpo ... estou tentando passar o objeto json, mas não está funcionando corretamente ...
VjyV
107

Atualização para Angualar 4.3+

Agora podemos usar em HttpClientvez deHttp

O guia está aqui

Código de amostra

const myheader = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
let body = new HttpParams();
body = body.set('username', USERNAME);
body = body.set('password', PASSWORD);
http
  .post('/api', body, {
    headers: myheader),
  })
  .subscribe();

Descontinuada

Ou você pode fazer assim:

let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', username);
urlSearchParams.append('password', password);
let body = urlSearchParams.toString()

Atualização out / 2017

Do angular4 + , não precisamos headers, ou .toString()coisas. Em vez disso, você pode fazer o exemplo abaixo

import { URLSearchParams } from '@angular/http';

Método POST / PUT

let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', username);
urlSearchParams.append('password', password);
this.http.post('/api', urlSearchParams).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
    )

Método GET / DELETE

    let urlSearchParams = new URLSearchParams();
    urlSearchParams.append('username', username);
    urlSearchParams.append('password', password);
    this.http.get('/api', { search: urlSearchParams }).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
    )

Para JSON application/jsonContent-Type

this.http.post('/api',
      JSON.stringify({
        username: username,
        password: password,
      })).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
      )
Frank Nguyen
fonte
14
Não se esqueça de importar a classe URLSearchParamsimport { URLSearchParams } from "angular2/http"
Sebastian Hernandez
10
minha importação parece diferente: import {URLSearchParams} de '@ angular / http';
cerca de
mas não existe uma maneira mais simples de enviar um objeto de formulário? Eu não vi nenhum tutorial usando URLSearchParams () para enviar uma postagem para um back-end com o Restful. como eles fazem? retornar this.http.post (this.actionUrl, body, {headers: this.headers}) .map ((response: Response) => response.json ()) .catch (this.handleError);
stackdave
Como isso funciona com booleanos? Recebendo um erro dizendo que não posso adicionar booleanos ou números, apenas strings (no
apêndice
Sobre booleano, talvez este tópico possa ajudá-lo stackoverflow.com/questions/14774907/…
Frank Nguyen
41

Em versões posteriores do Angular2, não há necessidade de definir manualmente o Content-Typecabeçalho e codificar o corpo se você passar um objeto do tipo correto como body.

Você simplesmente pode fazer isso

import { URLSearchParams } from "@angular/http"


testRequest() {
  let data = new URLSearchParams();
  data.append('username', username);
  data.append('password', password);

  this.http
    .post('/api', data)
      .subscribe(data => {
            alert('ok');
      }, error => {
          console.log(error.json());
      });
}

Dessa forma, o angular codificará o corpo para você e definirá o Content-Typecabeçalho correto .

PS Não se esqueça de importar URLSearchParamsde @angular/httpou não funcionará.

VStoykov
fonte
2
@VStoykov não funciona, você tem que .toString () nos parâmetros e você tem que especificar o tipo de conteúdo, e eu uso angular 4.0.3
Konrad
1
@ i'myourhuckleberry Deve funcionar mesmo no 4.0.3. Veja o código-fonte github.com/angular/angular/blob/4.0.3/packages/http/src/…
VStoykov
1
@VStoykov isso não funciona para mim e eu relatei como um bug no Github
Konrad
1
ESTÁ BEM. Nvm Tive que importar isso de "@ angular / http", caso contrário, ele reconhece o tipo, mas não é o tipo do angular.
Konrad
1
@ i'myourhuckleberry a importação foi a primeira linha no meu exemplo, mas provavelmente você a perdeu. Você pode usar os tipos embutidos no navegador FormDatae o angular irá definir Content-Typecomo multipart/form-datatambém funcionam.
VStoykov
10

então, apenas para torná-la uma resposta completa:

login(username, password) {
        var headers = new Headers();
        headers.append('Content-Type', 'application/x-www-form-urlencoded');
        let urlSearchParams = new URLSearchParams();
        urlSearchParams.append('username', username);
        urlSearchParams.append('password', password);
        let body = urlSearchParams.toString()
        return this.http.post('http://localHost:3000/users/login', body, {headers:headers})
            .map((response: Response) => {
                // login successful if there's a jwt token in the response
                console.log(response);
                var body = response.json();
                console.log(body);
                if (body.response){
                    let user = response.json();
                    if (user && user.token) {
                        // store user details and jwt token in local storage to keep user logged in between page refreshes
                        localStorage.setItem('currentUser', JSON.stringify(user)); 
                    }
                }
                else{
                    return body;
                }
            });
    }
droga
fonte
1
[ts] Argumento do tipo '{headers: RequestOptions; } 'não é atribuível ao parâmetro do tipo' RequestOptionsArgs '
Sonic Soul
2
@Sonic Soul é apenas: .. post ('/ api', body, headers) ... sem {} em torno dos cabeçalhos
Guenther
5

Essas respostas estão desatualizadas para aqueles que utilizam o HttpClient em vez do Http. Eu estava começando a enlouquecer pensando, "Fiz a importação de URLSearchParams, mas ainda não funciona sem .toString () e o cabeçalho explícito!"

Com HttpClient, use HttpParams em vez de URLSearchParams e observe a body = body.append()sintaxe para obter vários parâmetros no corpo, já que estamos trabalhando com um objeto imutável:

login(userName: string, password: string): Promise<boolean> {
    if (!userName || !password) {
      return Promise.resolve(false);
    }

    let body: HttpParams = new HttpParams();
    body = body.append('grant_type', 'password');
    body = body.append('username', userName);
    body = body.append('password', password);

    return this.http.post(this.url, body)
      .map(res => {
        if (res) {          
          return true;
        }
        return false;
      })
      .toPromise();
  }
333Matt
fonte
obrigado pela solução acima. Mas ao executar ng build --prod, os parâmetros do meu corpo se parecem com "{" params ": {" rawParams ":" "," queryEncoder ": {}," paramsMap ": {}}}:". Existe alguma solução alternativa.
Hemanth Poluru
4

Se alguém está lutando com a versão angular 4+ (a minha era 4.3.6) . Este foi o código de amostra que funcionou para mim.

Primeiro adicione as importações necessárias

import { Http, Headers, Response, URLSearchParams } from '@angular/http';

Em seguida, para a função api. É um exemplo de login que pode ser alterado de acordo com suas necessidades.

login(username: string, password: string) {
    var headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    let urlSearchParams = new URLSearchParams();
    urlSearchParams.append('email', username);
    urlSearchParams.append('password', password);
    let body = urlSearchParams.toString()

    return this.http.post('http://localhost:3000/api/v1/login', body, {headers: headers})
        .map((response: Response) => {
            // login successful if user.status = success in the response
            let user = response.json();
            console.log(user.status)
            if (user && "success" == user.status) {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('currentUser', JSON.stringify(user.data));
            }
        });
}
PC Krishnadas
fonte
0

Eu estava tendo problemas com cada abordagem usando vários parâmetros, mas funciona muito bem com um único objeto

api:

    [HttpPut]
    [Route("addfeeratevalue")]
    public object AddFeeRateValue(MyValeObject val)

angular:

var o = {ID:rateId, AMOUNT_TO: amountTo, VALUE: value};
return this.http.put('/api/ctrl/mymethod', JSON.stringify(o), this.getPutHeaders());


private getPutHeaders(){
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return new RequestOptions({
        headers: headers
        , withCredentials: true // optional when using windows auth
    });
}
Sonic Soul
fonte
1
O problema do OP é o tipo de conteúdo do aplicativo / x-www-form-urlencoded, sua resposta é um problema totalmente diferente.
Christian Ulbrich de
0
angular: 
    MethodName(stringValue: any): Observable<any> {
    let params = new HttpParams();
    params = params.append('categoryName', stringValue);

    return this.http.post('yoururl', '', {
      headers: new HttpHeaders({
        'Content-Type': 'application/json'
      }),
      params: params,
      responseType: "json"
    })
  }

api:   
  [HttpPost("[action]")]
  public object Method(string categoryName)
Muniyan
fonte
Olá, bem-vindo ao Stackoverflow. Obrigado por responder a esta pergunta, mas apenas postar um bloco de código é difícil de entender para o OP ou para qualquer pessoa que tenha essa pergunta no futuro. Você poderia editar sua pergunta e dar uma (breve) explicação sobre qual foi o problema que foi resolvido e como o resolveu, para nos ajudar a entender melhor sua solução?
Plutian
1
Olá @Plutian, quando passei o valor do 2º parâmetro da solicitação de postagem, ele me retornou os valores nulos da API, então passei esse 2º parâmetro como string vazia e passei os valores da propriedade params do 3º parâmetro, então esse método funcionou para mim
Muniyan
-2

Aterrissei aqui quando estava tentando fazer algo semelhante. Para um tipo de conteúdo application / x-www-form-urlencoded, você pode tentar usar isso para o corpo:

var body = 'username' =myusername & 'password'=mypassword;

com o que você tentou fazer, o valor atribuído ao corpo será uma string.

adongo
fonte
Como Joshua apontou, isso não é JavaScript válido nem TypeScript. Acho que o que você quis dizer é exatamente a resposta aceita atualmente.
Christian Ulbrich de