前端analysis | 3w & 1h

《angular8》- Angular HttpClient 30分钟轻松上手

2020-06-12


Angular8 HttpClient 30分钟深入了解下

前端开发,axios是标配的http请求发起libary, 采用的是Promise的方式。然后,Angular中采用的是另外一种形式Observable,观察订阅模式。Angular默认推荐采用内置的HTTPClient。
下面让我们开始今天的主题,HTTPClient

模块引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {HttpClientModule} from '@angular/common/http';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}

入门

GET请求

指定请求返回类型
1
2
this.http.get<Config>(this.configUrl)
.subscribe((data: Config) => this.config = { ...data });
  • get请求,明确返回的数据类型为Config,故请求形式为:
    1
    this.http.get<Config>()...
  • 请求返回后,进行数据转换
不指定请求返回类型
1
2
this.http.get(this.configUrl)
.subscribe((data: any) => this.config = { ...data });

等效于

1
2
this.http.get<Object>(this.configUrl)
.subscribe((data: Object) => this.config = { ...data });

问题1: 如果服务端,返回的数据就是一个text文本,譬如Hello,world,你猜会怎么样?

请求url携带参数
  • 方法一:HttpParams 形式set
    1
    2
    3
    4
    5
    6
    7
    # 必须.链式set,否则参数空
    const params = new HttpParams()
    .set('orderBy', '"$key"')
    .set('limitToFirst', "1");

    this.http.get(this.configUrl,{params})
    .subscribe((data: any) => this.config = { ...data });
  • 方法二: fromString
    1
    2
    3
    4
    5
    6
    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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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方式传参
1
2
3
4
5
   const params = new HttpParams({
fromString: 'orderBy="$key"&limitToFirst=1'
});

this.http.request("GET",this.configUrl, { params })
header传参
  • 方法一: HttpHeaders
    1
    2
    3
    4
    5
    6
     const headers = new HttpHeaders()
    .set("X-CustomHeader", "custom header value");

    this.http.get(this.configUrl,{ headers })
    .do(console.log)
    .map(data => _.values(data));
  • 方法二:{} 字面量
    1
    2
    3
    4
    5
    6
    7
    8
     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方法请求参数的定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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即可。

    1
    2
    this.http.get(this.configUrl,{responseType:'text'})
    .subscribe((data: any) => this.config = { ...data });
解答问题二:
1
2
3
this.http.get<Config>(
this.configUrl, { observe: 'response' })
.subscribe((data: any) => this.config = { ...data });
那么event 是干什么的呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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处理
1
2
3
4
5
6
7
8
9
10
const parallel$ = Observable.forkJoin(
this.http.get(url1),
this.http.get(url2)
);

parallel$.subscribe(
values => {
console.log("all values", values)
}
);
串行多个Get请求
1
2
3
4
5
6
7
8
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)
);
异常处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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...")
);
请求拦截
  • 定义鉴权拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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);
    }
    }
  • 配置拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @NgModule({
    declarations: [
    AppComponent
    ],
    imports: [
    BrowserModule,
    HttpClientModule
    ],
    providers: [
    [
    {
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true
    }
    ]
    ],
    bootstrap: [AppComponent]
    })
    export class AppModule {
    }

    参考

  • angular

  • angular 官网

推荐

Angular8状态管理NgRx

前端Rollup+RxJs响应式编程实践

Angular8 httpclient简单入门

20个你值得了解的Angular开源项目

angular8 日常开发填坑指南

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏