2015-11-26 27 views
52

サービス内のhttpリクエストからの応答の構造化と処理に関する質問があります。私はが(ちょうど...私は愛するそれをOUT-テストを開始Psの...それに取り組んとgithubのを経由して貢献してきたすべての人々をありがとう)Angular2.alpha46活字体を使用していますAngular2ハンドリングhttp応答

だから次のことを行ってください。

ログイン-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])) 
    } 
} 

、このコンポーネントからの私は、サービスは次のようになり、ユーザーのログインを私のhttpリクエストを収容する私のUserServiceのインポート:

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

は、私は何をしたい呼び出しが戻るhttpリクエストの後に応答を処理できるようにすることです。たとえば、ユーザーの資格情報が無効な場合は、バックエンドから401応答を戻します。私の質問は、応答を処理し、結果をコンポーネントを呼び出すコンポーネントに戻すための最良の方法です。成功メッセージを表示するか、エラーメッセージを表示するためにビューを操作できます。

現時点ではログイン中の私は現在応答を処理していません。元のコンポーネントにコールバックしていますが、これは正しい方法ではないと感じていますか?この典型的なシナリオで誰かが何をするかについて、誰かに光を当てることはできますか?

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' 
} 

、この場合には戻って細かいコールはありますか、これは、観察や約束をよりよく処理することができます。私のようなサブスクライブ関数の最初のパラメータで応答を処理しませんか?

私が求めていますどのような結論が戻っログインにHTTPレスポンスからの応答を処理し、user.service.tsからフォームのビューで状況を処理するためのベストプラクティスは何です... -form.component.ts

+0

次のリリースで(参照[これはコミット(https://github.com/robwormald/angular/commit/cf338e8ec7cc8cfbe6e66eae51e271ee825c891f))非HTTPステータスコードを取得すると、 'Http'エラーが発生します。今のところ、 'map()'で応答を処理し、そこのステータスをチェックしてErrorを投げたり、値を渡したりすることができます。 –

+0

迅速な返信Ericに感謝します。クール!私はそれを考えていましたが、いくつかのことがまだ議論の対象になっていることを認識しています...だから確かめるために...マップの応答ステータスを今のところ処理し、あなたはそれをより良いやり方でやり直すことができますか? – Nige

+0

あなたはコールバックを一切必要としません、私の答えを見てください。それはうまくいけばあなたの質問に答えるでしょう:D –

答えて

70

更新アルファ47

(以下alpha46とするための)以下の答えがもう必要でないアルファ47のように。これで、Httpモジュールは返されたエラーを自動的に処理します。だから今アルファ46

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

を次のように簡単で、

の下にあなたはsubscribe前に、map(...)で応答を処理することができます。

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 

ここでは、簡単な例を挙げてplnkrです。

次のリリースでは、200未満および299を超えるすべてのステータスコードが自動的にエラーをスローするため、これは必要ではないことに注意してください。自分でチェックする必要はありません。詳細はcommitにチェックしてください。

+0

あなたがリンクしているplnkrが正しく動作していないそれを修正してください。私は状態コードを取得する必要がありますが、REST APIはどうやってこれを取得できますか? –

+0

@PardeepJain働いていないということはどういう意味ですか?要求を失敗させたい場合は、最初の 'get'をコメントアウトし、2番目のコメントを解除します。 –

+1

res.statusとres.json()の両方を返す場合はどうすればよいですか? –

9

は、angle2 2.1です。1(データ)、(エラー)パターンを使用して例外を捕捉することができなかったので、.catch(...)を使用して実装しました。

戻り

(観測可能な)::それは.retry .MAPなどのような他のすべての観察可能なチェーン方法documentationから

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 

で使用することができますので、

それはうれしいですソースシーケンスが正常に終了するまで、連続したソースシーケンスからの要素を含む観測可能なシーケンス。

+0

質問:observableは何か他のものではありません_not_エラーですか?それ以外の場合は、私は再び何をポイントにエラーを再挑戦している? – Vic

+1

あなたは何を意味するのかわかりません。 observableはエラーではありません。通常は購読可能なデータオブジェクトを保持します。エラーが発生すると、catchブロックがトリガーされます。その場合、チェーンを続けることができるようにスローが起こらなければならない。それを処理する方法を決定するのは他の加入者次第です。たとえば、この結果を他の場所で購読することができ、エラーを別の方法で処理したいことがあります。 –

+0

私は今理解しています。その言葉は私を混乱させた。しかし、私は今それの利益を見る。ありがとう – Vic

2

サービス:アプリで

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

this.itemService.toSaveItem(item).then(
    (res) => { console.log('success', res) }, 
    (err) => { console.log('error', err) } 
) 
関連する問題