it-roy-ru.com

Как заставить Angular2 POST использовать x-www-form-urlencoded

У меня есть проект, который должен использовать Angular2 (окончательный вариант) для публикации на старом унаследованном сервере Tomcat 7, предоставляющем API-интерфейс REST-ish с использованием страниц .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}`;`

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

60
Damon Kaswell

Вы можете сделать это, используя 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(...);
76
Brad

Для Angular 4.3 +/5 + (New 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 вещи, чтобы заставить это работать как ожидалось:

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

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

67
Mick

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

DoNOTset Content-Type header, angular исправит это для вас!

25
Johan Kvint

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

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

this.http.post(url, content);

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

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

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

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

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

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