Angular2 - parámetros de solicitud HTTP POST

91

Estoy tratando de hacer una solicitud POST pero no puedo hacer que funcione:

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

Básicamente, quiero replicar esta solicitud http (no ajax) como si se originara en un formulario html:

URL: / api

Parámetros: nombre de usuario y contraseña

Christopher
fuente
Eche un vistazo a stackoverflow.com/a/34758630/5043867 y stackoverflow.com/a/34823818/5043867 ¡ esto explicará todo sobre la solicitud POST en profundidad!
Pardeep Jain
@PardeepJain No estoy tratando de consumir una API. Solo para simular un POST originado por un formulario html.
Christopher
también verifique aquí, publique un archivo con user_namey password, stackoverflow.com/a/45879409/2803344
Belter

Respuestas:

49

Creo que el cuerpo no es correcto para un application/x-www-form-urlencodedtipo de contenido. Podrías intentar usar esto:

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

Espero que te ayude, Thierry

Thierry Templier
fuente
sí, con ese tipo de contenido en el encabezado, es la única solución que pasa valores "a la antigua" en lugar de la cadena json
Nather Webber
Ésta no es una buena respuesta. Use URLSearchParams en su lugar, como se menciona a continuación con más votos a favor.
Mick
Para las personas del futuro que vengan de una búsqueda en Google, esta no es la mejor respuesta (¡no te ofendas Thierry! Tu respuesta sigue siendo técnicamente correcta :)). La respuesta de V Stoykov es hasta ahora la más precisa. ps asegúrese de hacerlo import { URLSearchParams } from "@angular/http"y no el predeterminado, por lo que 1) no necesita hacerlo .toString, y 2) no necesita establecer el tipo de contenido. Angular lo inferirá automáticamente por usted (consulte github.com/angular/angular/blob/4.4.4/packages/http/src/… )
Eran Medan
Hola ! si quiero pasar el servicio de publicación con el encabezado -> tipo de contenido como 'aplicación / json', lo que necesito pasar en el cuerpo ... Estoy tratando de pasar el objeto json pero no funciona correctamente ...
VjyV
107

Actualización para Angualar 4.3+

Ahora podemos usar en HttpClientlugar deHttp

La guía está aquí

Código de muestra

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

Obsoleto

O puedes hacer esto:

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

Actualización Oct / 2017

Desde angular4 + , no necesitamos headers, ni .toString()cosas. En su lugar, puede hacer como el siguiente ejemplo

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 el tipo de application/jsoncontenido JSON

this.http.post('/api',
      JSON.stringify({
        username: username,
        password: password,
      })).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
      )
Frank Nguyen
fuente
14
No olvide importar la clase URLSearchParamsimport { URLSearchParams } from "angular2/http"
Sebastian Hernandez
10
mi importación se ve diferente: importar {URLSearchParams} desde '@ angular / http';
Dang
pero, ¿no hay una forma más sencilla de enviar un objeto de formulario? No vi ningún tutorial usando URLSearchParams () para enviar una publicación para un backend con restful. como lo hacen return this.http.post (this.actionUrl, body, {headers: this.headers}) .map ((response: Response) => response.json ()) .catch (this.handleError);
stackdave
¿Cómo funciona esto con booleanos? Recibo un error que dice que no puedo agregar booleanos o números, solo cadenas (en
anexo
Acerca de boolean, tal vez este tema pueda ayudarlo a stackoverflow.com/questions/14774907/…
Frank Nguyen
41

En versiones posteriores de Angular2, no es necesario configurar manualmente el Content-Typeencabezado y codificar el cuerpo si pasa un objeto del tipo correcto como body.

Simplemente puedes hacer esto

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

De esta manera, angular codificará el cuerpo por usted y establecerá el Content-Typeencabezado correcto .

PD: no olvides importar URLSearchParams desde @angular/httpo no funcionará.

VStoykov
fuente
2
@VStoykov no funciona, tienes que .toString () en los parámetros y tienes que especificar el tipo de contenido, y yo uso angular 4.0.3
Konrad
1
@ i'myourhuckleberry Debería funcionar incluso en 4.0.3. Mire el código fuente github.com/angular/angular/blob/4.0.3/packages/http/src/…
VStoykov
1
@VStoykov no funciona para mí y lo he informado como un error en Github
Konrad
1
OKAY. Nvm Tuve que importar esto desde "@ angular / http", de lo contrario, reconoce el tipo pero no es el tipo de angular.
Konrad
1
@ i'myourhuckleberry la importación fue la primera línea en mi ejemplo, pero probablemente te la perdiste. Desde el construido en los tipos en el navegador puede utilizar FormData, y angulares configurará Content-Typecomo multipart/form-dataque también el trabajo.
VStoykov
10

así que solo para que sea una respuesta 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;
                }
            });
    }
maldición
fuente
1
[ts] Argumento de tipo '{encabezados: RequestOptions; } 'no se puede asignar al parámetro de tipo' RequestOptionsArgs '
Sonic Soul
2
@Sonic Soul es solo: .. publicación ('/ api', cuerpo, encabezados) ... sin {} alrededor de los encabezados
Guenther
5

Todas estas respuestas están desactualizadas para aquellos que utilizan HttpClient en lugar de Http. Estaba empezando a volverme loco pensando, "¡He importado URLSearchParams pero todavía no funciona sin .toString () y el encabezado explícito!"

Con HttpClient, use HttpParams en lugar de URLSearchParams y observe la body = body.append()sintaxis para lograr múltiples parámetros en el cuerpo, ya que estamos trabajando con un objeto inmutable:

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
fuente
gracias por la solución anterior. Pero cuando se ejecuta ng build --prod, los parámetros de mi cuerpo se ven como "{" params ": {" rawParams ":" "," queryEncoder ": {}," paramsMap ": {}}}:". Hay algún trabajo alrededor.
Hemanth Poluru
4

Si alguien está luchando con la versión angular 4+ (la mía era 4.3.6) . Este fue el código de muestra que funcionó para mí.

Primero agregue las importaciones requeridas

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

Luego, para la función api. Es una muestra de inicio de sesión que se puede cambiar según sus necesidades.

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));
            }
        });
}
Krishnadas PC
fuente
0

Tenía problemas con cada enfoque que usaba múltiples parámetros, pero funciona bastante bien con un solo 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
fuente
1
El problema de OP es el tipo de contenido de la aplicación / x-www-form-urlencoded, su respuesta es un problema totalmente diferente.
Christian Ulbrich
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
fuente
Hola y bienvenido a Stackoverflow. Gracias por responder esta pregunta, pero publicar un bloque de código es difícil de entender para el OP o para cualquiera que se encuentre con esta pregunta en el futuro. ¿Podría editar su pregunta y dar una explicación (breve) sobre cuál fue el problema que resolvió y cómo lo resolvió para ayudarnos a comprender mejor su solución?
Plutian
1
Hola @Plutian, cuando pasé el valor en el segundo parámetro de la solicitud de publicación, me devolvió los valores nulos en la API, así que pasé ese segundo parámetro como una cadena vacía y pasé los valores en la propiedad params del tercer parámetro, por lo que este método funcionó para mí
Muniyan
-2

Aterricé aquí cuando intentaba hacer algo similar. Para un tipo de contenido application / x-www-form-urlencoded, puede intentar usar esto para el cuerpo:

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

con lo que intentaste hacer, el valor asignado a body será una cadena.

adongo
fuente
Como señaló Joshua, esto no es JavaScript ni TypeScript válidos. Creo que lo que quisiste decir es exactamente la respuesta aceptada actualmente.
Christian Ulbrich