Подтвердить что ты не робот

Как заставить Angular2 выполнить POST с помощью x-www-form-urlencoded

У меня есть проект, который должен использовать Angular2 (final) для публикации на старый, старый сервер Tomcat 7, предоставляющий несколько REST-ish API, используя страницы .jsp.

Это отлично работало, когда проект был просто простым JQuery-приложением, выполняющим запросы AJAX. Однако объем проекта вырос настолько, что его необходимо будет переписать с использованием более современных рамок. Angular2 выглядит фантастически для работы, за одним исключением: он отказывается выполнять POST-запросы, используя что-либо, но как данные формы, которые API не извлекает. API ожидает, что все будет urlencoded, опираясь на синтаксис Java request.getParameter("param"), чтобы извлечь отдельные поля.

Это отключено из моего 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));
                }
            }
        );
    }
}

Независимо от того, каким я настроил тип содержимого заголовка, он всегда попадает в некодированные данные формы. Это не соответствует заголовку, который я устанавливаю.

Кто-нибудь еще столкнулся с этим? Как вы собираетесь форсировать Angular2 данные POST в формате, который может быть прочитан старым Java API с помощью request.getParameter("param")?

Изменить: для всех, кто находит это в будущем, решение на самом деле очень просто. Установите тело сообщения следующим образом:

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

См. пример Брэда ниже.

4b9b3361

Ответ 1

Вы можете сделать это, используя URLSearchParams, поскольку тело запроса и angular автоматически настроит тип контента на application/x-www-form-urlencoded и правильно закодирует тело.

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

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

Причина, по которой он не работает в настоящее время, заключается в том, что вы не кодируете данные тела в правильном формате и не задаете правильные параметры заголовка.

Вам нужно закодировать тело следующим образом:

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

Вам нужно установить параметры заголовка следующим образом:

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

Ответ 2

Для Angular 4.3 +/5 + (Новый HTTPClient) используйте следующее:

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 => {
        //...
    });

Обратите внимание на 3 вещи, чтобы они работали, как ожидалось:

  • Используйте URLSearchParams для вашего тела.
  • Преобразование тела в строку
  • Установить тип содержимого заголовка

Внимание. Старые браузеры нуждаются в polyfill! Я использовал: npm i url-search-params-polyfill --save, а затем добавил в polyfills.ts: import 'url-search-params-polyfill';

Ответ 3

Для тех, кто все еще ищет ответ, я решил это с помощью Angular 5 и 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);

Устанавливает НЕ заголовок Content-Type, Angular исправляет это для вас!

Ответ 4

Вот что сработало для меня с Angular 7:

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

this.http.post(url, payload);

Нет необходимости явно устанавливать заголовок при таком подходе.

Обратите внимание, что объект HttpParams является неизменным. Таким образом, выполнение чего-то вроде следующего не будет работать, оно даст вам пустое тело:

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

this.http.post(url, payload);

Ответ 5

Я нашел это решение после нескольких часов работы над этим вопросом.

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

}

Ответ 6

Добавление из Brad, тела, которое вам нужно будет вызвать body.toString() и поместить его как тело запроса.

Ответ 7

Ребята, я работал над этим некоторое время, и благодаря этому сообщению от Джоша Морони https://www.joshmorony.com/integrating-an-ionic-application-with-a-nodejs-backend/ я понял, в чем проблема. По сути, когда я начал тестировать свой API, я использовал POSTMAN, и он работал отлично, но когда дело дошло до реализации его с помощью Ionic Angular, это стало проблемой. Решение в этом посте только об импорте body-parser и использовании его в качестве промежуточного программного обеспечения приложения, такого как app.use(bodyParser.json()), в корневой файл (индекс) на стороне сервера.

Надеюсь, это поможет, спасибо!

Ответ 8

При использовании angular форм большинство параметров будет отправлено как объекты, следовательно, ваша функция входа в систему, скорее всего, будет иметь этот объект form.value = {username: 'someone', password:'1234', grant_type: 'password'} в качестве параметра

чтобы отправить этот объект как x-www-form-urlencoded, ваш код будет

export class AuthService {
    private headers = new HttpHeaders(
        {
            'Content-Type':  'application/x-www-form-urlencoded',
            Accept: '*/*',
        }
    );
  constructor(private http: HttpClient) { }

  login(data): Observable<any> {
    const body = new HttpParams({fromObject: data});
    const options = { headers: this.headers};
    return this.http.post('${environment.baseUrl}/token', body.toString(), options);
  }