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

Krzysztof
źródł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

Thierry Templier
źródło
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()));
      }
      )
Frank Nguyen
źródło
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.

VStoykov
źródło
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;
                }
            });
    }
cholera
źródło
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();
  }
333Matt
źródło
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));
            }
        });
}
Krishnadas PC
źródło
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)
Muniyan
źródło
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
    });
}
Sonic Soul
źródło
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.

adongo
źródło
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,