接上篇,雖然一會兒從建立項目就到了http通訊,看上去是有點猴急,但沒辦法,走到哪裏就算哪裏吧。在這裏,我描述三個場景,即系統的註冊與登陸,及登陸後的操做。html
一、註冊場景,前端頁面傳入用戶名密碼,經過一個api接口傳到後臺,在後臺對這用戶及密碼進行保存;前端
二、登陸場景,前端用戶傳入用戶名及密碼,經過api接口傳到後臺,在後臺進行配對,若是配對成功,則在後臺派發(返回)一個令牌(id_token,下同),經過這個令牌做爲用戶已經登陸的惟一憑證,須要保存到用戶本地存儲(localStorage),之後做後續操做;node
三、登陸後操做,當用戶須要受權操做時,那麼首先得獲取本地存儲(localStorage)中的令牌,將令牌傳到後臺,若是匹配成功,則容許操做,不然不容許操做。git
之後三個場景大致描述了一個系統註冊登陸的思路。下面,我將從這三個思路出發,講述Angular2中http與後臺通訊的過程。github
在繼續以前,咱們須要一些準備工做,即建立一個後臺服務,包括註冊、登陸及查詢這三個接口。由於這裏不關注後臺怎麼建立,因此我也從網上一位小哥這裏找到現成的後臺服務,這裏包括有三個接口分別以下:npm
http://localhost:3001/users http://localhost:3001/sessions/create http://localhost:3001/api/protected/random-quote
下載及方法:json
git clone https://github.com/auth0/nodejs-jwt-authentication-sample.git npm install node server.js
按照上面的步驟,後臺服務就算準備完成,能夠繼續往下看了。api
接下來,建立界面元素post-component.html服務器
<form (ngSubmit)="register(registerForm.value)" #registerForm="ngForm"> <div class="text-center"> <h2>註冊</h2> </div> <div class="form-group"> <label for="username">Name</label> <input type="text" class="form-control" id="username" required [(ngModel)]="model.username" name="username"> </div> <div class="form-group"> <label for="password">Alter Ego</label> <input type="text" class="form-control" id="password" required [(ngModel)]="model.password" name="password"> </div> <button type="submit" class="btn btn-success">Submit</button> </form> <form (ngSubmit)="onLogin(loginForm.value)" #loginForm="ngForm"> <div class="text-center"> <h2>登陸</h2> </div> <div class="form-group"> <label for="username2">Name</label> <input type="text" class="form-control" id="username2" required [(ngModel)]="model.username2" name="username2"> </div> <div class="form-group"> <label for="password2">Alter Ego</label> <input type="text" class="form-control" id="password2" required [(ngModel)]="model.password2" name="password2"> </div> <button type="submit" class="btn btn-success">Submit</button> </form> <button id="input" (click)="getSecretQuote()">登陸以後才能獲取數據</button>
接下來建立PostComponent.ts組件session
@Component({ selector: 'post-client', templateUrl: './post-component.html', }) export class PostComponent { model: any; constructor(private http: Http) { this.model = {}; } //把代碼寫這裏啦 }
這樣,咱們就已經建立好工做區模板,能夠盡情在哪裏寫東西了。
在進行以前,咱們看下angular2中,http api方法的傳參數形式
http.get(url: string, options?: RequestOptionsArgs) : Observable<Response> http.post(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response>
能夠看到,根據其參數url地址, body:any及options?: RequestOptionsArgs參數來提交對應的數據信息,其中body表示傳遞到服務器端的數據信息,options表示頭部驗證信息。兩個方法都返回一個可觀察對象Observable,咱們能夠經過subscribe方法獲得裏面的值並做後繼處理。這樣,咱們能夠獲得如下代碼處理方法
this.http.post(url: string, body: any, options?: RequestOptionsArgs).subscribe(function (data) { console.log(data) })
以上的處理方式並無什麼太大的問題,但總感受仍是有點小小的欠缺。
咱們經過Http以及Jsonp的api接口能夠知道,默認返回值都是可觀察對象 Observable< Response >。能夠把可觀察對象 Observable 看作一個由某些「源」發佈的事件流。 經過 訂閱 到可觀察對象 Observable ,咱們監聽(subscribe)這個流中的事件。 在這些訂閱中,咱們指定了當 Web 請求生成了一個成功事件 ( 有效載荷是英雄數據 ) 或失敗事件 ( 有效載荷是錯誤對象 ) 時該如何採起行動,如示例中所示。
咱們的服務能夠返回 HTTP 響應對象Response。但這可不是一個好主意! 數據服務的重點在於,對消費者隱藏與服務器交互的細節。其實上,咱們最關心的仍是獲取到的返回數據信息,這時候咱們就能夠利用RxJS庫來對事件流進行一些額外的處理。
RxJS("Reactive Extensions" 的縮寫)是一個被 Angular 承認的第三方庫,它實現了異步可觀察對象 (asynchronous observable) 模式。Rxjs庫中包含不少對事件流進行處理的方法,例如map,distinctUntilChanged等操做符。
針對返回數據是json格式的響應對象,能夠把Response解析成 JavaScript 對象——只要調一下 response.json() 就能夠了,這時候咱們就能夠利用map操做符來進行處理,例如,咱們將上面的方法升級下
this.http.post(url: string, body: any, options?: RequestOptionsArgs).map((rsp:Response)=>{ return rsp.json() }) .subscribe((data) => { console.log(data); });
注意,這裏.map用到了rxjs庫,須要導入這個庫。
雖然 Angular 的 http 客戶端 API 返回的是 Observable<Response> 類型的對象,但咱們也能夠把它轉成 Promise<Response>。這很容易,只須要調用可觀察對象 Observable< Response >的方法toPromise()就可以進行轉化。
this.http.post(url: string, body: any, options?: RequestOptionsArgs).toPromise() .then((rsp: Response) => { console.log(rsp) });
經過上面的講述,如今執行http通訊也變得簡單多了。上代碼
register(data) { var username = data.username; var password = data.password; var body = "username=" + username + "&password=" + password + "&extra=color"; var headers = new Headers(); headers.append('Content-Type', 'application/x-www-form-urlencoded'); this.http.post('http://localhost:3001/users', body, { headers: headers }) .map(res => res.json()) .subscribe( data => console.log(data), err => console.log(err), () => console.log('Register Complete') ); }
onLogin(data) { var username = data.username2; var password = data.password2; var body = "username=" + username + "&password=" + password + "&extra=color"; var headers = new Headers(); headers.append('Content-Type', 'application/x-www-form-urlencoded'); this.http.post('http://localhost:3001/sessions/create', body, { headers: headers }) .map(res => res.json()) .subscribe( data => { localStorage.setItem('id_token', data.id_token), console.log(data) }, err => console.log(err), () => console.log('Register Complete') ); }
這裏須要注意,localStorage.setItem('id_token', data.id_token)
這句代碼,表明將獲取的令牌保存到本地存儲,這是表明本用戶已經登陸的惟一憑證。
getSecretQuote() { var jwt = localStorage.getItem('id_token'); var authHeader = new Headers(); if (jwt) { authHeader.append('Authorization', 'Bearer ' + jwt); } this.http.get('http://localhost:3001/api/protected/random-quote', { headers: authHeader }) .map(res => res.text()) .subscribe( data => console.log(data), err => console.log(err), () => console.log('Secret Quote Complete') ); }
在這裏,執行查詢前須要把本地存儲中的令牌帶到頭部,
var jwt = localStorage.getItem('id_token');
這樣後臺就能夠在查詢前對令牌進行比對,若是比對成功,則返回結果。
這樣,一個簡單的註冊--登陸--查詢思路便講解完成了