Angular8 HttpClient 30分钟深入了解下
前端开发,axios是标配的http请求发起libary, 采用的是Promise的方式。然后,Angular中采用的是另外一种形式Observable,观察订阅模式。Angular默认推荐采用内置的HTTPClient。 下面让我们开始今天的主题,HTTPClient
模块引入
import {HttpClientModule} from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
入门
GET请求
指定请求返回类型
this.http.get<Config>(this.configUrl)
.subscribe((data: Config) => this.config = { ...data });
- get请求,明确返回的数据类型为Config,故请求形式为:
this.http.get<Config>()...
- 请求返回后,进行数据转换
不指定请求返回类型
this.http.get(this.configUrl)
.subscribe((data: any) => this.config = { ...data });
等效于
this.http.get<Object>(this.configUrl)
.subscribe((data: Object) => this.config = { ...data });
「问题1: 如果服务端,返回的数据就是一个text文本,譬如Hello,world,你猜会怎么样?」
请求url携带参数
- 方法一:HttpParams 形式set
# 必须.链式set,否则参数空
const params = new HttpParams()
.set('orderBy', '"$key"')
.set('limitToFirst', "1");
this.http.get(this.configUrl,{params})
.subscribe((data: any) => this.config = { ...data });
- 方法二: fromString
const params = new HttpParams({ fromString: 'orderBy="$key"&limitToFirst=1' });
this.http.get(this.configUrl,{params}) .subscribe((data: any) => this.config = { ...data });
「问题2: 如果前端想拿到后端api header头中参数,怎么办?」
POST
this.http.post(url,
{
"courseListIcon": "...",
"description": "TEST",
"iconUrl": "..",
"longDescription": "...",
"url": "new-url"
})
.subscribe(
(res) => {
console.log("POST call successful value returned in body",
res);
},
error => {
console.log("POST call in error", error);
},
() => {
console.log("The POST observable is now completed.");
});
}
DELETE
this.http.delete(url1)
.subscribe(
(res) => {
console.log("DELETE call successful value returned in body",
res);
},
error => {
console.log("DELETE call in error", error);
},
() => {
console.log("The DELETE observable is now completed.");
});
}
PATCH
this.http.patch(url,
{
"description": "Angular Tutorial For Beginners PATCH TEST",
})
.subscribe(
(res) => {
console.log("PATCH call successful value returned in body",
res);
},
error => {
console.log("PATCH call in error", error);
},
() => {
console.log("The PATCH observable is now completed.");
});
}
进阶
GET请求
request方式传参
const params = new HttpParams({
fromString: 'orderBy="$key"&limitToFirst=1'
});
this.http.request("GET",this.configUrl, { params })
header传参
- 方法一: HttpHeaders
const headers = new HttpHeaders()
.set("X-CustomHeader", "custom header value");
this.http.get(this.configUrl,{ headers })
.do(console.log)
.map(data => _.values(data));
- 方法二:{} 字面量
const headers = {
"X-CustomHeader", "custom header value",
'content-type': 'application/json'
}
this.http.get(this.configUrl,{ headers })
.do(console.log)
.map(data => _.values(data));
解答问题1:
- 我们看一下源码针对Get方法请求参数的定义
get(url: string, options?: {
headers?: HttpHeaders | {
[header: string]: string | string[];
};
# 默认值有: response| body| event
observe?: 'body';# 默认读取的是response中的body
params?: HttpParams | {
[param: string]: string | string[];
};
reportProgress?: boolean;
# 默认值有: arraybuffer | json | blob |text
responseType?: 'json';# 这里,ts参数类型可选,默认值json,
withCredentials?: boolean;
}): Observable<Object>;
- 故从源码我们可以知道,后端返回Hello,world,前端get方法会返回JSON解析异常。此时我们设置下responseType即可。
this.http.get(this.configUrl,{responseType:'text'})
.subscribe((data: any) => this.config = { ...data });
解答问题二:
this.http.get<Config>(
this.configUrl, { observe: 'response' })
.subscribe((data: any) => this.config = { ...data });
那么event 是干什么的呢?
const request = new HttpRequest(
"POST", this.uploadURL, {},{observe: 'events',reportProgress: true});
this.http.request(request)
.subscribe(
event => {
# 文件上传进度判定
if (event.type === HttpEventType.DownloadProgress) {
console.log("Download progress event", event);
}
if (event.type === HttpEventType.UploadProgress) {
console.log("Upload progress event", event);
}
if (event.type === HttpEventType.Response) {
console.log("response received...", event.body);
}
}
);
高级
GET请求
并行多个Get处理
const parallel$ = Observable.forkJoin(
this.http.get(url1),
this.http.get(url2)
);
parallel$.subscribe(
values => {
console.log("all values", values)
}
);
串行多个Get请求
const sequence$ = this.http.get<Config>(url1)
.switchMap(config => {
config.description+= ' - TEST ';
return this.http.put(url2,config)
});
sequence$.subscribe(
values => console.log("result observable ", values)
);
异常处理
this.http
.get("/api/simulate-error")
.catch( error => {
// here we can show an error message to the user,
// for example via a service
console.error("error catched", error);
return Observable.of({description: "Error Value Emitted"});
})
.subscribe(
val => console.log('Value emitted successfully', val),
error => {
console.error("This line is never called ",error);
},
() => console.log("HTTP Observable completed...")
);
请求拦截
- 定义鉴权拦截器
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor}
from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {
}
intercept(req: HttpRequest<any>,
next: HttpHandler):Observable<HttpEvent<any>> {
const clonedRequest = req.clone({
headers: req.headers.set(
'X-CustomAuthHeader',
authService.getToken())
});
console.log("new headers", clonedRequest.headers.keys());
return next.handle(clonedRequest);
}
}
- 配置拦截器
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
[
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
],
bootstrap: [AppComponent]
})
export class AppModule {
}