web-dev-qa-db-fra.com

Comment forcer Angular2 à POST en utilisant x-www-form-urlencoded

J'ai un projet qui doit utiliser Angular2 (final) pour publier sur un ancien serveur Tomcat 7, fournissant une API quelque peu REST-ish utilisant des pages .jsp.

Cela fonctionnait bien lorsque le projet était une simple application JQuery qui exécutait des requêtes AJAX. Cependant, la portée du projet a pris de l'ampleur, de sorte qu'il devra être réécrit en utilisant un cadre plus moderne. Angular2 semble fantastique pour le travail, à une exception près: il refuse d’exécuter des requêtes POST en utilisant l’option autre chose que des données de formulaire, que l’API n’extrait pas. L'API s'attend à ce que tout soit codé en url, en s'appuyant sur la syntaxe request.getParameter("param") de Java pour extraire des champs individuels.

Ceci est un extrait de user.service.ts:

import { Injectable }    from '@angular/core';
import { Headers, Response, Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class UserService {
    private loggedIn = false;
    private loginUrl = 'http://localhost:8080/mpadmin/api/login.jsp';
    private headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});

    constructor(private http: Http) {}

    login(username, password) {
        return this.http.post(this.loginUrl, {'username': username, 'password':  password}, this.headers)
            .map((response: Response) => {
                let user = response.json();
                if (user) {
                    localStorage.setItem('currentUser', JSON.stringify(user));
                }
            }
        );
    }
}

Quoi que je définisse comme type de contenu d'en-tête, il finit toujours par arriver sous forme de données de formulaire non codées. Il ne respecte pas l'en-tête que je mets.

Quelqu'un d'autre a-t-il rencontré cela? Comment faire pour forcer Angular2 à POST des données dans un format lisible par une ancienne API Java à l'aide de request.getParameter("param")?

Edit : Pour quiconque trouve cela dans le futur, la solution est en réalité très simple. Définissez le corps du message comme ceci:

let body = `username=${username}&password=${password}`;`

Voir l'exemple de Brad ci-dessous.

48
Damon Kaswell

Vous pouvez le faire en utilisant URLSearchParams comme corps de la requête et angular définira automatiquement le type de contenu sur application/x-www-form-urlencoded et encodera correctement le corps.

let body = new URLSearchParams();
body.set('username', username);
body.set('password', password);

this.http.post(this.loginUrl, body).map(...);

La raison pour laquelle cela ne fonctionne pas actuellement pour vous est que vous ne codez pas les données du corps au format correct et que vous ne définissez pas les options d'en-tête correctement.

Vous devez encoder le corps comme ceci:

let body = `username=${username}&password=${password}`;

Vous devez définir les options d'en-tête comme ceci:

this.http.post(this.loginUrl, body, { headers: headers }).map(...);
76
Brad

Pour Angular 4.3 +/5 + (New HTTPClient), utilisez les éléments suivants:

let body = new URLSearchParams();
body.set('user', username);
body.set('password', password);

let options = {
    headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};

this.http
    .post('//yourUrl.com/login', body.toString(), options)
    .subscribe(response => {
        //...
    });

Notez 3 choses pour que cela fonctionne comme prévu:

  1. Utilisez URLSearchParams pour votre corps
  2. Convertir le corps en chaîne
  3. Définir le type de contenu de l'en-tête

Attention : Les anciens navigateurs ont besoin d'un polyfill! J'ai utilisé: npm i url-search-params-polyfill --save et ensuite ajouté à polyfills.ts: import 'url-search-params-polyfill';

67
Mick

Pour ceux qui cherchent encore une réponse, voici comment je l'ai résolu avec Angular 5 et HttpClient:

const formData = new FormData();

// append your data
formData.append('myKey1', 'some value 1');
formData.append('myKey1', 'some value 2');
formData.append('myKey3', true);

this.httpClient.post('apiPath', formData);

NePASdéfinir l'en-tête Content-Type, angular résoudra ce problème pour vous!

25
Johan Kvint

C'est ce qui a fonctionné pour moi avec Angular 7:

const payload = new HttpParams()
  .set('username', username)
  .set('password', password);

this.http.post(url, content);

Pas besoin de définir explicitement l'en-tête avec cette approche.

Notez que l'objet HttpParams est immuable. Donc, faire quelque chose comme ce qui suit ne fonctionnera pas, cela vous donnera un corps vide:

const payload = new HttpParams();
payload.set('username', username);
payload.set('password', password);

this.http.post(url, content);
4
Robert Hegner

Les gars sur lesquels je travaille depuis un certain temps et grâce au message de Josh Morony https://www.joshmorony.com/integrating-an-ionic-application-with-a-nodejs-backend/ J'ai compris quel était le problème. En fait, lorsque j'ai commencé à tester mon API, j'utilisais POSTMAN et tout fonctionnait parfaitement, mais lorsqu'il s'agissait de l'implémenter avec Ionic Angular, cela devenait un problème. La solution présentée dans cet article consiste uniquement à importer body-parser et à l'utiliser comme middleware d'application tel que celui-ci app.use(bodyParser.json()) sur votre fichier racine (index) côté serveur.

J'espère que cela aidera, Merci!

0
WinnersProx

J'ai découvert cette solution après avoir travaillé plusieurs heures sur ce problème

login(userName: string, password: string) {
const headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append( 'No-Auth', 'True');

const body = new URLSearchParams();
body.set('username', userName);
body.set('password', password);
body.set('grant_type', 'password');

return this.http.post(
    this.baseUrl + '/token'
   , body.toString()
   , { headers: headers }
  )
  .pipe(map(res => res.json()))
  .pipe(map(res => {
    localStorage.setItem('auth_token', res.auth_token);
    return true;
  }))
  .pipe(catchError((error: any) => {
    return Observable.throw(error);
  }));

}

0
khaleel