個人博客遷移至 http://www.sulishibaobei.com 處;
Angular 4.3.0-rc.0 版本已經發布🐦。在這個版本中,我們等到了一個令人興奮的新功能 - HTTPClient API 的改進版本;
HttpClient 是已有 Angular HTTP API 的演進,它在一個單獨的 @angular/common/http 包中。這是為了確保現有的代碼庫可以緩慢遷移到新的 API;
大多數前端應用都需要通過 HTTP 協議與后端服務器通訊。現代瀏覽器支持使用兩種不同的 API 發起 HTTP 請求:XMLHttpRequest 接口和 fetch() API;
@angular/common/http中的HttpClient類,Angular 為應用程序提供了一個簡化的 API 來實現 HTTP 功能。它基於瀏覽器提供的XMLHttpRequest接口。 HttpClient帶來的其它優點包括:可測試性、強類型的請求和響應對象、發起請求與接收響應時的攔截器支持,以及更好的、基於可觀察(Observable)對象的錯誤處理機制;
1.如何使用httpClient;
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {HttpClientModule} from '@angular/common/http';
@NgModule({
imports: [
BrowserModule,
// Include it under 'imports' in your application module
// after BrowserModule.
HttpClientModule,
],
})
export class MyAppModule {}
注意:導入方式和HttpModule一樣的,記得要在BrowserModule后面導入;區別是:在@angular/common/http 模塊里面,而不是@angular/http中
這樣我們可以使用這些啦:
class HttpClient { request(first: string|HttpRequest<any>, url?: string, options: {...}): Observable<any> delete(url: string, options: {...}): Observable<any> get(url: string, options: {...}): Observable<any> head(url: string, options: {...}): Observable<any> jsonp<T>(url: string, callbackParam: string): Observable<T> options(url: string, options: {...}): Observable<any> patch(url: string, body: any|null, options: {...}): Observable<any> post(url: string, body: any|null, options: {...}): Observable<any> put(url: string, body: any|null, options: {...}): Observable<any> }
2.發起一個請求來獲取Json數據;
首先創建一個json文件,其實就是上一篇的同一個json文件:
{
"data": [
{ "id": 1, "name": "Windstorm" },
{ "id": 2, "name": "Bombasto" },
{ "id": 3, "name": "Magneta" },
{ "id": 4, "name": "Tornado" }
]
}
怎么調用Http請求呢?
2.1 app.componment.ts;
import { Component,OnInit } from '@angular/core';
import {HttpClient} from '@angular/common/http'; /*注釋1*/
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private http:HttpClient){}
datas:string[];
ngOnInit(){
this.http.get('./assets/heroes.json').subscribe(data=>{ /*注釋2*/
this.datas=data['data'];
console.log(this.datas)
})
}
}
注意:
注釋1: 組件中引入的是HttpClient,也是在單獨的庫,@angular/common/http中;
之前的項目里面引入的一直都是http,這就是改版后的區別;
注釋2:現在 JSON 是默認的數據格式,我們不需要再進行顯式的解析;this.http.get('xx').subscribe();
之前的還需要res.json()去手動轉;
還有一點要注意:我並沒有去hero.service.ts里面去操作了,而是直接在組件中發請求獲取數據,這樣更加簡單明了;
<div> <ul *ngFor="let data of datas"> <li>{{data.id}} {{data.name}}</li> </ul> </div>
html代碼還是一樣簡單,並沒有改變;

這是相比較之前的Http簡單的方式;
get(url: string, options: { headers?: HttpHeaders, observe?: HttpObserve, params?: HttpParams, reportProgress?: boolean, responseType?: 'arraybuffer'|'blob'|'json'|'text', withCredentials?: boolean, }): Observable<any>
這是get方法詳解,請注意,返回的都是observable對象,而不是使用promise了;
3.響應體的檢查
3.1上面的代碼中:
datas:string[]; //定義一個接口來描述這個類型的正確形態
this.datas=data['data']; /*注釋1*/
注釋1:
我們取json對象data值時要data['data'],而不是之前的data.data了;如果改成:
this.datas=data.data;
會報錯:
does not exist on type 'Object
那是因為HttpClient把 JSON 格式的響應體解析成了一個Object,它並不知道這個對象的形態應該是什么。所以我們應該告訴你需要取得data是個什么類型;這也是更符合typescript語法的做法;
4. 如果將要獲取的不是JSON文件如何?
this.http.get('/assets/1.txt',{responseType:'text'}).subscribe(
data=>console.log(data)
)
注意:這樣我們就要指定需要獲取的文本格式;
控制台將會打印我的1.txt中的內容:www.sulishibaobei.com
5.如何帶參查詢數據
const params = new HttpParams()
.set('id', '1').set('name','Windstorm')
this.cus=this.http.get('assets/heroes.json',{params})
.do(console.log)
.map(data=>
console.log( _.values(data))
);
引入:httpParams參數:
import {HttpClient, HttpParams} from '@angular/common/http';
我們通過鏈式語法調用set()方法,構建了params對象;每當set()方法被調用時,都會包含新的值進來,並且防止之前對象不被修改;
http://localhost:4200/assets/heroes.json?id=1&name=Windstorm
請求的鏈接地址將會是這樣的形式;這個有點像http里添加url參數;
還可以設置Headers;
const headers = new HttpHeaders().set("X-CustomHeader", "custom header value");
還有其他的請求,之后會逐一分析;
另外還有幾點比較重要的:
多行並發發送請求和順序發送請求,避免發送重復請求;
避免發送重復請求
import 'rxjs/add/operator/shareReplay';
const httpGet = this.http
.get("assets/heroes.json")
.map(data => _.values(data))
.shareReplay();
這樣即使你將 httpGet再賦值給另一個變量,或重復調用也不會再次請求了
並行發送 HTTP 請求的一種方法是使用 RxJs 中的 forkjoin 操作符:
import 'rxjs/add/observable/forkJoin';
Requests() {
const result = Observable.forkJoin(
this.http.get('/assets/heroes.json'),
this.http.get('/assets/heroes.json')
);
result.subscribe(
values => {
console.log("all values", values)
}
);
}
順序發送請求 sequentialRequests() { const sequence$ = this.http.get<Hero>('/assets/heroes.json') .switchMap(hero => { hero.id+= ' - TEST '; return this.http.put('/assets/heroes.json', hero) }); sequence$.subscribe(); }
6. 攔截器 (攔截所有的請求和響應這也是@angular/common/http的核心特性之一)
它能聲明一些攔截器,攔在應用和后端之間。當應用程序發起一個請求時,攔截器可以在請求被發往服務器之前先轉換這個請求。並且在應用看到服務器發回來的響應之前,轉換這個響應。這對於處理包括認證和記錄日志在內的一系列工作都非常有用。
6.1 如何寫一個攔截器
import {Injectable} from '@angular/core'; import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse} from '@angular/common/http'; import {Observable} from 'Rxjs/Observable'; @Injectable() export class NoopInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(req).map(event => { if (event instanceof HttpResponse) { if (event.status === 401) { // JWT expired, go to login } } return event; } } }
1.intercept是一個方法,它把一個請求對象轉換成一個返回這個響應的可觀察對象(Observable)。從這個意義上說,每個攔截器都要完全自己處理這個請求;
2.響應攔截器可以通過在 next.handle(req) 返回的流對象 (即 Observable 對象) 上應用附加的 Rx 操作符來轉換響應事件流對象;
內部可以做自己的處理操作;
但是此時攔截器還未使用在組件上;
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: NoopInterceptor,
multi: true,
}],
})
export class AppModule {}
providers里面配置我們的信息;
注意multi: true選項。這是必須的,因為它會告訴 Angular 這個 HTTP_INTERCEPTORS 表示的是一個數組,而不是單個的值;
