Angular2 - parametry żądania Http POST


94

Próbuję wysłać żądanie POST, ale nie mogę go uruchomić:

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

Zasadniczo chcę replikować to żądanie http (nie ajax), tak jakby zostało zapoczątkowane przez formularz HTML:

URL: / api

Params: nazwa użytkownika i hasło


spójrz na te stackoverflow.com/a/34758630/5043867 i stackoverflow.com/a/34823818/5043867, które szczegółowo wyjaśniają wszystko o żądaniu POST!
Pardeep Jain

@PardeepJain Nie próbuję korzystać z interfejsu API. Wystarczy zasymulować POST utworzony z formularza HTML.
Christopher,

sprawdź także tutaj, opublikuj plik za pomocą user_namei password, stackoverflow.com/a/45879409/2803344
Belter

Odpowiedzi:


49

Myślę, że application/x-www-form-urlencodedtreść nie jest poprawna dla typu zawartości. Możesz spróbować użyć tego:

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

Mam nadzieję, że ci to pomoże, Thierry


tak z tym typem treści w nagłówku, jest to jedyne rozwiązanie przekazujące wartości „po staremu” zamiast łańcucha json
Nather Webber

To nie jest dobra odpowiedź. Zamiast tego użyj URLSearchParams, jak wspomniano poniżej, z większą liczbą głosów za.
Mick

Dla ludzi z przyszłości, pochodzących z wyszukiwarki Google, to nie jest najlepsza odpowiedź (bez obrazy Thierry! Twoja odpowiedź jest nadal poprawna technicznie :)). Jak dotąd odpowiedź V Stoykova jest najdokładniejsza. ps upewnij się, że import { URLSearchParams } from "@angular/http"nie jest to domyślny, więc 1) nie musisz na nim robić .toStringi 2) nie musisz ustawiać typu zawartości. Angular wywnioskuje to automatycznie (patrz github.com/angular/angular/blob/4.4.4/packages/http/src/… )
Eran Medan

Cześć ! jeśli chcę przekazać usługę pocztową z nagłówkiem -> typ treści, taki jak
``

107

Aktualizacja dla Angualar 4.3+

Teraz możemy użyć HttpClientzamiastHttp

Przewodnik jest tutaj

Przykładowy kod

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

Przestarzałe

Lub możesz to zrobić:

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

Aktualizacja październik / 2017

Od angular4 + , nie potrzebujemy headers, lub .toString()pasz. Zamiast tego możesz zrobić jak poniżej przykład

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

Metoda 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 metoda

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

Dla typu application/jsonzawartości JSON

this.http.post('/api',
      JSON.stringify({
        username: username,
        password: password,
      })).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
      )

14
Nie zapomnij zaimportować klasy URLSearchParamsimport { URLSearchParams } from "angular2/http"
Sebastian Hernandez,

10
mój import wygląda inaczej: import {URLSearchParams} z „@ angular / http”;
dang

ale czy nie ma prostszego sposobu na wysłanie obiektu formularza? nie widziałem żadnego samouczka używającego URLSearchParams () do wysyłania postów do zaplecza z restful. jak oni to robią? return this.http.post (this.actionUrl, body, {headers: this.headers}) .map ((response: Response) => response.json ()) .catch (this.handleError);
stackdave

Jak to działa w przypadku wartości logicznych? Pojawia się błąd informujący, że nie mogę dodawać wartości logicznych ani liczb, tylko ciągi znaków (w dołączaniu)
JohnAndrews

O boolean, może ten temat pomoże ci stackoverflow.com/questions/14774907/ ...
Frank Nguyen

41

W późniejszych wersjach Angular2 nie ma potrzeby ręcznego ustawiania Content-Typenagłówka i kodowania treści, jeśli przekazujesz obiekt odpowiedniego typu jako body.

Po prostu możesz to zrobić

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

W ten sposób angular zakoduje dla Ciebie body i ustawi poprawny Content-Typenagłówek.

PS Nie zapomnij importować URLSearchParamsz @angular/httplub to nie zadziała.


2
@VStoykov to nie działa, musisz .toString () na parametrach i musisz określić typ zawartości, a ja używam angular 4.0.3
Konrad

1
@ i'myourhuckleberry Powinien działać nawet na 4.0.3. Spójrz na kod źródłowy github.com/angular/angular/blob/4.0.3/packages/http/src/…
VStoykov

1
@VStoykov to nie działa dla mnie i zgłosiłem to jako błąd na Github
Konrad

1
OK. Nvm Musiałem zaimportować to z „@ angular / http”, w przeciwnym razie rozpoznaje typ, ale nie jest to typ kątowy.
Konrad

1
@ i'myourhuckleberry import był pierwszym wierszem w moim przykładzie, ale prawdopodobnie go przegapiłeś. Z typów wbudowanych w przeglądarce możesz korzystać FormData, a kątowy ustawisz Content-Typejako multipart/form-dataktóry również działa.
VStoykov

10

żeby była to pełna odpowiedź:

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] Argument typu „{headers: RequestOptions; } 'nie można przypisać do parametru typu' RequestOptionsArgs '
Sonic Soul

2
@Sonic Soul to tylko: .. post ('/ api', body, headers) ... bez {} wokół nagłówków
Guenther,

5

Te odpowiedzi są nieaktualne dla osób korzystających z HttpClient zamiast Http. Zacząłem szaleć, myśląc: „Zaimportowałem URLSearchParams, ale nadal nie działa bez .toString () i jawnego nagłówka!”

W przypadku HttpClient użyj HttpParams zamiast URLSearchParams i zanotuj body = body.append()składnię, aby uzyskać wiele parametrów w treści, ponieważ pracujemy z niezmiennym obiektem:

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

dzięki za powyższe rozwiązanie. Ale kiedy uruchamiam ng build --prod, moje parametry ciała wyglądają jak "{" params ": {" rawParams ":" "," queryEncoder ": {}," paramsMap ": {}}}:". Czy jest jakieś obejście?
Hemanth Poluru

4

Jeśli ktoś boryka się z wersją kątową 4+ (u mnie było 4.3.6) . To był przykładowy kod, który działał dla mnie.

Najpierw dodaj wymagane importy

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

Następnie dla funkcji API. To próbka logowania, którą można zmienić zgodnie ze swoimi potrzebami.

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)

Cześć i witaj w Stackoverflow. Dziękuję za odpowiedź na to pytanie, ale samo wysłanie bloku kodu jest trudne do zrozumienia dla OP lub kogokolwiek, kto napotka to pytanie w przyszłości. Czy byłbyś w stanie edytować swoje pytanie i podać (krótkie) wyjaśnienie, jaki problem został rozwiązany i jak go rozwiązałeś, aby pomóc nam lepiej zrozumieć Twoje rozwiązanie?
Plutian

1
Cześć @Plutian, kiedy przekazałem wartość drugiego parametru żądania postu, zwracając mi wartości null w api, więc przekazałem ten drugi parametr jako pusty ciąg i przekazałem wartości właściwości params trzeciego parametru, więc ta metoda zadziałała dla mnie
Muniyan

0

Miałem problemy z każdym podejściem wykorzystującym wiele parametrów, ale działa to całkiem dobrze z jednym obiektem

api:

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

kątowy:

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

1
Problemem OP jest typ treści aplikacji / x-www-form-urlencoded, twoja odpowiedź to zupełnie inny problem.
Christian Ulbrich,

-2

Wylądowałem tutaj, kiedy próbowałem zrobić podobną rzecz. W przypadku typu zawartości application / x-www-form-urlencoded możesz spróbować użyć tego dla treści:

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

z tym, co próbowałeś zrobić, wartość przypisana do body będzie ciągiem.


Jak zauważył Joshua, nie jest to poprawny JavaScript ani TypeScript. Myślę, że miałeś na myśli dokładnie obecnie zaakceptowaną odpowiedź.
Christian Ulbrich,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.