Angular2 - параметры запроса Http POST

94

Я пытаюсь отправить запрос POST, но не могу заставить его работать:

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

Я в основном хочу воспроизвести этот http-запрос (не ajax), как будто он был создан с помощью html-формы:

URL: / api

Параметры: имя пользователя и пароль

Кристофер
источник
взгляните на этот stackoverflow.com/a/34758630/5043867 и stackoverflow.com/a/34823818/5043867, это подробно объяснит все о запросе POST!
Пардип Джайн
@PardeepJain, я не пытаюсь использовать API. Просто чтобы имитировать POST, созданный html-формой.
Кристофер
также проверьте здесь, user_namepassword
Belter

Ответы:

49

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

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

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

Тьерри Темплиер
источник
да, с этим типом содержимого в заголовке, это единственное решение, передающее значения «старым способом» вместо строки json
Натер Уэббер,
Это плохой ответ. Вместо этого используйте URLSearchParams, как указано ниже, с большим количеством голосов.
Мик
Людям из будущего, пришедшим из поиска Google, это не лучший ответ (без обид, Тьерри! Ваш ответ все еще технически правильный :)). Ответ В. Стойкова пока самый точный. ps убедитесь, что он установлен, import { URLSearchParams } from "@angular/http"а не установлен по умолчанию, поэтому 1) вам не нужно делать .toStringэто и 2) вам не нужно устанавливать тип содержимого. Angular сделает это автоматически для вас (см. Github.com/angular/angular/blob/4.4.4/packages/http/src/… )
Эран Медан
Здравствуй ! если я хочу передать почтовую службу с заголовком -> тип содержимого, например 'application / json', что мне нужно передать в теле .... я пытаюсь передать объект json, но он не работает должным образом ...
VjyV
107

Обновление для Angualar 4.3+

Теперь мы можем использовать HttpClientвместоHttp

Гид здесь

Образец кода

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

Не рекомендуется

Или можно сделать так:

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

Обновление октябрь / 2017

От angular4 + нам ничего не нужно headersили .toString()прочее. Вместо этого вы можете сделать как показано ниже

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

Метод 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()));
      }
    )

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

Для типа application/jsonсодержимого JSON

this.http.post('/api',
      JSON.stringify({
        username: username,
        password: password,
      })).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
      )
Франк Нгуен
источник
14
Не забудьте импортировать класс URLSearchParamsimport { URLSearchParams } from "angular2/http"
Себастьян Эрнандес
10
мой импорт выглядит иначе: импорт {URLSearchParams} из '@ angular / http';
dang
но нет более простого способа отправить объект формы? я не видел никакого руководства, использующего URLSearchParams () для отправки сообщения для бэкэнда с успокоением. как они это делают? вернуть this.http.post (this.actionUrl, body, {заголовки: this.headers}) .map ((response: Response) => response.json ()) .catch (this.handleError);
stackdave 01
Как это работает с логическими значениями? Появляется сообщение об ошибке, в котором говорится, что я не могу складывать логические значения или числа, только строки (в добавлении)
Джон Эндрюс
О логических значениях, может быть, эта тема поможет вам stackoverflow.com/questions/14774907/…
Фрэнк Нгуен,
41

В более поздних версиях Angular2 нет необходимости вручную настраивать Content-Typeзаголовок и кодировать тело, если вы передаете объект правильного типа как body.

Вы просто можете это сделать

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

Таким образом, angular закодирует тело за вас и установит правильный Content-Typeзаголовок.

PS Не забывайте импортировать URLSearchParamsиз, @angular/httpиначе не получится.

В.С.тойков
источник
2
@VStoykov это не работает, вам нужно .toString () в параметрах, и вы должны указать тип контента, а я использую angular 4.0.3
Конрад
1
@ i'myourhuckleberry Должно работать даже на 4.0.3. Посмотрите исходный код github.com/angular/angular/blob/4.0.3/packages/http/src/…
VStoykov
1
@VStoykov у меня не работает, и я сообщил об этом как об ошибке на Github
Конрад,
1
ОК. Nvm Мне пришлось импортировать это из «@ angular / http», иначе он распознает тип, но это не тип angular.
Конрад
1
@ i'myourhuckleberry импорт был первой строкой в ​​моем примере, но, вероятно, вы его пропустили. Из встроенных типов в браузере вы можете использовать FormData, и угловой будет установлен в Content-Typeкачестве multipart/form-dataкоторой также работу.
VStoykov 03
10

так что просто чтобы дать полный ответ:

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;
                }
            });
    }
черт возьми
источник
1
[ts] Аргумент типа '{заголовки: RequestOptions; } 'не может быть назначен параметру типа' RequestOptionsArgs '
Sonic Soul
2
@Sonic Soul, это просто: .. сообщение ('/ api', body, headers) ... без {} вокруг заголовков
Гюнтер
5

Все эти ответы устарели для тех, кто использует HttpClient, а не Http. Я начал сходить с ума, думая: «Я выполнил импорт URLSearchParams, но он все еще не работает без .toString () и явного заголовка!»

С HttpClient используйте HttpParams вместо URLSearchParams и обратите внимание на body = body.append() синтаксис для достижения нескольких параметров в теле, поскольку мы работаем с неизменяемым объектом:

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();
  }
333матт
источник
спасибо за вышеуказанное решение. Но при запуске ng build --prod мои параметры тела выглядят как "{" params ": {" rawParams ":" "," queryEncoder ": {}," paramsMap ": {}}}:". Есть ли обходной путь.
Хемант Полуру
4

Если кто-то борется с angular версией 4+ (у меня была 4.3.6) . Это был пример кода, который работал у меня.

Сначала добавьте требуемый импорт

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

Затем для функции api. Это образец входа в систему, который можно изменить в соответствии с вашими потребностями.

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));
            }
        });
}
Кришнадас ПК
источник
1
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)
Муньян
источник
Привет и добро пожаловать в Stackoverflow. Спасибо за ответ на этот вопрос, но просто опубликовать блок кода сложно для понимания OP или любого, кто столкнется с этим вопросом в будущем. Сможете ли вы отредактировать свой вопрос и дать (краткое) объяснение того, какая проблема была решена и как вы ее решили, чтобы помочь нам лучше понять ваше решение?
Plutian
1
Привет @Plutian, когда я передал значение 2-го параметра почтового запроса, он вернул мне нулевые значения на api, поэтому я передал этот 2-й параметр как пустую строку, и я передал значения в свойстве params 3-го параметра, поэтому этот метод сработал для меня
Muniyan
0

У меня были проблемы с каждым подходом, использующим несколько параметров, но он довольно хорошо работает с одним объектом

api:

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

угловой:

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
источник
1
Проблема OP - это тип содержимого application / x-www-form-urlencoded, ваш ответ - совершенно другая проблема.
Кристиан Ульбрих
-2

Я приземлился здесь, когда пытался сделать то же самое. Для типа содержимого application / x-www-form-urlencoded вы можете попробовать использовать это для тела:

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

с тем, что вы пытались сделать, значение, присвоенное телу, будет строкой.

Адонго
источник
Как указал Джошуа, это недопустимый JavaScript или TypeScript. Думаю, вы имели в виду именно тот ответ, который сейчас принят.
Кристиан Ульбрих