2015-11-26 10 views
52

Ich habe nur eine Frage bezüglich der Strukturierung und Verarbeitung von Antworten von http Anfragen innerhalb eines Dienstes. Ich bin mit Angular2.alpha46 Typoskript (Just begann es zu testen out- was ich liebe ... Ps .. Vielen Dank an alle die Menschen, die daran zu arbeiten haben und über Github beitragen)Angular2 Handhabung http Antwort

So nehmen Sie die folgenden Schritte aus:

Login-form.component.ts

import {Component, CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2'; 
import {UserService} from '../../shared/service/user.service'; 
import {Router} from 'angular2/router'; 
import {User} from '../../model/user.model'; 
import {APP_ROUTES, Routes} from '../../core/route.config'; 

@Component({ 
    selector: 'login-form', 
    templateUrl: 'app/login/components/login-form.component.html', 
    directives: [CORE_DIRECTIVES, FORM_DIRECTIVES] 
}) 

export class LoginFormComponent { 
    user: User; 
    submitted: Boolean = false; 

    constructor(private userService:UserService, private router: Router) { 
     this.user = new User(); 
    } 

    onLogin() { 
     this.submitted = true; 

     this.userService.login(this.user, 
      () => this.router.navigate([Routes.home.as])) 
    } 
} 

von dieser Komponente ich meine Userservice einführen, die meine http Anfrage Haus wird der Benutzer den Service sieht wie folgt anmelden:

user.service.ts

import {Inject} from 'angular2/angular2'; 
import {Http, HTTP_BINDINGS, Headers} from 'angular2/http'; 
import {ROUTER_BINDINGS} from 'angular2/router'; 
import {User} from '../../model/user.model'; 

export class UserService { 

    private headers: Headers; 

    constructor(@Inject(Http) private http:Http) { 
    } 

    login(user: User, done: Function) { 
     var postData = "email=" + user.email + "&password=" + user.password; 

     this.headers = new Headers(); 
     this.headers.append('Content-Type', 'application/x-www-form-urlencoded'); 

     this.http.post('/auth/local', postData, { 
       headers: this.headers 
      }) 
      .map((res:any) => res.json()) 
      .subscribe(
       data => this.saveJwt(data.id_token), 
       err => this.logError(err), 
       () => done() 
      ); 
    } 

    saveJwt(jwt: string) { 
     if(jwt) localStorage.setItem('id_token', jwt) 
    } 

    logError(err: any) { 
     console.log(err); 
    } 
} 

Was ich tun möchte ist in der Lage sein, die Antwort der Anruf kehrt nach der HTTP-Anforderung zu behandeln. Wenn zum Beispiel die Benutzeranmeldeinformationen ungültig sind, gebe ich eine 401-Antwort vom Backend zurück. Meine Frage ist, wo der beste Weg ist, die Antwort zu behandeln und das Ergebnis zurück zu der Komponente zurückzuschicken, wo ich die Methode aufgerufen habe, damit ich die Ansicht manipulieren kann, um entweder die Erfolgsmeldung anzuzeigen oder eine Fehlermeldung anzuzeigen.

Im Moment in meinem Service unter Login bin ich derzeit nicht mit der Antwort Ich mache nur einen Rückruf zurück zu der ursprünglichen Komponente, aber ich denke, das ist nicht der richtige Weg, um darüber zu gehen? Kann jemand etwas Licht auf das werfen, was sie in diesem typischen Szenario tun würden? Werde ich übernehme die Antwort im ersten Parameter der abonnieren Funktion wie:

login(user: User, done: Function) { 
    var postData = "email=" + user.email + "&password=" + user.password; 

    this.headers = new Headers(); 
    this.headers.append('Content-Type', 'application/x-www-form-urlencoded'); 

    this.http.post('/auth/local', postData, { 
      headers: this.headers 
     }) 
     .map((res:any) => res.json()) 
     .subscribe(
      (data) => { 
       // Handle response here 
       let responseStat = this.handleResponse(data.header) 

       // Do some stuff 
       this.saveJwt(data.id_token); 

       // do call back to original component and pass the response status 
       done(responseStat); 
      }, 
      err => this.logError(err) 
     ); 
} 

handleResponse(header) { 
    if(header.status != 401) { 
     return 'success' 
    } 

    return 'error blah blah' 
} 

ist einen Rückruf fein in diesem Fall oder kann dies mit einer beobachtbaren oder ein Versprechen, besser behandelt werden?

Zum Abschluss, was ich fragen, ist ... Was ist die beste Praxis die Antwort von dem HTTP-Antwort und behandeln Sie den Status im Hinblick auf die Form aus den user.service.ts zurück zum Login zu handhaben -form.component.ts

+0

In der nächsten Version (siehe [diese begehen] (https://github.com/robwormald/angular/commit/cf338e8ec7cc8cfbe6e66eae51e271ee825c891f)) "Http" wird Fehler, wenn Sie nicht 200 Statuscodes erhalten. Für jetzt können Sie die Antwort in 'map()' behandeln, den Status dort überprüfen und einen Fehler werfen oder den Wert übergeben. –

+0

Danke für die schnelle Antwort Eric. Cool! Ich dachte, dass und ich bin mir bewusst, dass einige Sachen noch zur Diskussion stehen ... Also nur um zu bestätigen ... Würden Sie sagen, es ist komplett zu finden, um den Antwortstatus in der Karte für jetzt zu behandeln und den Wert in einem Rückruf zu übergeben? Könnten Sie es besser machen oder genügt ein Rückruf? – Nige

+0

Sie brauchen den Rückruf überhaupt nicht, sehen Sie meine Antwort und es wird hoffentlich Ihre Frage beantworten: D –

Antwort

70

Update-alpha 47

Ab alpha 47 die folgende Antwort (für alpha46 und unten) ist nicht mehr erforderlich. Jetzt behandelt das HTTP-Modul automatisch die zurückgegebenen Fehler. So ist jetzt so einfach wie

folgt
http 
    .get('Some Url') 
    .map(res => res.json()) 
    .subscribe(
    (data) => this.data = data, 
    (err) => this.error = err); // Reach here if fails 

Alpha 46 und unter

können Sie die Antwort in der map(...) handhaben, vor dem subscribe.

http 
    .get('Some Url') 
    .map(res => { 
    // If request fails, throw an Error that will be caught 
    if(res.status < 200 || res.status >= 300) { 
     throw new Error('This request has failed ' + res.status); 
    } 
    // If everything went fine, return the response 
    else { 
     return res.json(); 
    } 
    }) 
    .subscribe(
    (data) => this.data = data, // Reach here if res.status >= 200 && <= 299 
    (err) => this.error = err); // Reach here if fails 

Hier ist ein plnkr mit einem einfachen Beispiel.

Beachten Sie, dass dies in der nächsten Version nicht erforderlich ist, da alle Statuscodes unter 200 und über 299 automatisch einen Fehler auslösen, so dass Sie sie nicht selbst überprüfen müssen. Überprüfen Sie diese commit für weitere Informationen.

+0

PLNKR Sie haben verlinkt funktioniert nicht richtig, bitte beheben Sie es. Ich muss den Statuscode erhalten, während REST API schlägt, wie kann ich das bekommen? –

+0

@PardeepJain was meinst du mit nicht funktioniert? Wenn Sie die Anfrage zum Scheitern machen wollen, kommentieren Sie einfach das erste "get" und kommentieren Sie das zweite. –

+1

Was ist, wenn ich res.status und res.json() zusammen zurückgeben möchte? –

9

in angular2 2.1.1 Ich konnte die Ausnahme nicht mit dem Muster (Daten), (Fehler) abfangen, also implementierte ich sie mit .catch (...).

Es ist schön, weil es mit allen anderen beobachtbaren gekettet Methoden wie .retry .map usw. verwendet werden können

import {Observable} from 'rxjs/Rx'; 


    Http 
    .put(...) 
    .catch(err => { 
    notify('UI error handling'); 
    return Observable.throw(err); // observable needs to be returned or exception raised 
    }) 
    .subscribe(data => ...) // handle success 

von documentation:

Returns

(beobachtbar): Ein beobachtbare Sequenz, die Elemente aus aufeinanderfolgenden Quellensequenzen enthält, bis eine Quellensequenz erfolgreich beendet wird.

+0

Frage: Kann das Observable etwas anderes sein, das _nicht_ ein Fehler ist? Sonst, wenn ich den Fehler erneut wiederhole, was ist der Punkt? – Vic

+1

nicht sicher, was du meinst. beobachtbar ist kein Fehler. normalerweise werden die Datenobjekte übertragen, die abonniert werden können. Wenn ein Fehler auftritt, wird der catch-Block ausgelöst. In diesem Fall muss ein Wurf stattfinden, damit die Kette weiterlaufen kann. Es liegt an anderen Teilnehmern zu entscheiden, wie sie damit umgehen sollen.Zum Beispiel können Sie dieses Ergebnis an anderen Stellen abonnieren, und sie möchten möglicherweise Fehler anders behandeln. –

+0

Ich verstehe jetzt. Dieses Wort hatte mich verwirrt. Aber ich sehe jetzt den Vorteil davon. Vielen Dank – Vic

2

Der Service:

import 'rxjs/add/operator/map'; 

import { Http } from '@angular/http'; 
import { Observable } from "rxjs/Rx" 
import { Injectable } from '@angular/core'; 

@Injectable() 
export class ItemService { 
    private api = "your_api_url"; 

    constructor(private http: Http) { 

    } 

    toSaveItem(item) { 
    return new Promise((resolve, reject) => { 
     this.http 
     .post(this.api + '/items', { item: item }) 
     .map(res => res.json()) 
     // This catch is very powerfull, it can catch all errors 
     .catch((err: Response) => { 
      // The err.statusText is empty if server down (err.type === 3) 
      console.log((err.statusText || "Can't join the server.")); 
      // Really usefull. The app can't catch this in "(err)" closure 
      reject((err.statusText || "Can't join the server.")); 
      // This return is required to compile but unuseable in your app 
      return Observable.throw(err); 
     }) 
     // The (err) => {} param on subscribe can't catch server down error so I keep only the catch 
     .subscribe(data => { resolve(data) }) 
    }) 
    } 
} 

In der App:

this.itemService.toSaveItem(item).then(
    (res) => { console.log('success', res) }, 
    (err) => { console.log('error', err) } 
)