Angular 6 HttpClient 快速入门

2019-11-05 16:10:34 浏览数 (1)

本教程将介绍如何在 Angular 6.x 中使用 HttpClient 发送 Http 请求,如 get、post、put 和 delete 请求。在 Angular 4.3 版本之后引入了 HttpClientModule 模块,该模块提供的 HttpClient 服务是已有 Angular HTTP API 的演进,它在一个单独的 @angular/common/http 包中。

废话不多说,现在让我们来看一下如何在 Angular 6.x 中使用 HttpClientModule 模块。

导入 HttpClientModule 模块

代码语言:javascript复制
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";

import { AppComponent } from "./app.component";

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

需要注意的是,现在 JSON 是默认的数据格式,我们不需要再进行显式的解析。即我们不需要再使用以下代码:

代码语言:javascript复制
http.get(url).map(res => res.json()).subscribe(...)

现在我们可以这样写:

代码语言:javascript复制
http.get(url).subscribe(...)

发送 Get 请求

代码语言:javascript复制
import { Component, OnInit } from "@angular/core";
import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http";

import { Observable } from "rxjs";
import { tap } from "rxjs/operators";

interface Todo {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

@Component({
  selector: "app-root",
  template: `
    <ul *ngIf="todos$ | async as todos else noData">
        <li *ngFor="let todo of todos">
            <span>Title: {{todo.title}}</span> —— 
            <span>Completed: {{todo.completed}}</span>
        </li> 
    </ul>
    <ng-template #noData>No Data Available</ng-template>
`
})
export class AppComponent implements OnInit {
  todos$: Observable<Todo[]>;
  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.todos$ = this.http
      .get<Todo[]>(
        "https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10"
      )
      .pipe(tap(console.log));
  }
}

设置查询参数

假设发送 Get 请求时,需要设置对应的查询参数,预期的 URL 地址如下:

代码语言:javascript复制
https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10
创建 HttpParams 对象
代码语言:javascript复制
import { HttpClient, HttpParams } from "@angular/common/http";

const params = new HttpParams().set("_page", "1").set("_limit", "10");

ngOnInit() {
  this.todos$ = this.http
    .get<Todo[]>("https://jsonplaceholder.typicode.com/todos", { params })
    .pipe(tap(console.log));
}

需要注意的是,我们通过链式语法调用 set() 方法,构建 HttpParams 对象。这是因为 HttpParams 对象是不可变的,通过 set() 方法可以防止该对象被修改。

每当调用 set() 方法,将会返回包含新值的 HttpParams 对象,因此如果使用下面的方式,将不能正确的设置参数。

代码语言:javascript复制
const params = new HttpParams();

params.set("_page", "1")
params.set("_limit", "10");
使用 fromString
代码语言:javascript复制
const params = new HttpParams({fromString: "_page=1&_limit=10"});
使用 fromObject
代码语言:javascript复制
const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });
使用 request API
代码语言:javascript复制
ngOnInit() {
  this.users$ = this.http
    .request("GET", "https://jsonplaceholder.typicode.com/todos", { params })
    .pipe(tap(console.log));
}

获取完整响应

默认情况下,HttpClient 服务返回的是响应体,有时候我们需要获取响应头的相关信息,这时你可以设置请求 options 对象的 observe 属性值为 response 来获取完整的响应对象。

代码语言:javascript复制
this.http.get("https://jsonplaceholder.typicode.com/todos/1", {
  observe: "response"
})
.subscribe(res => {
   console.dir("Response: "   res.status);
});

设置响应类型

如果你期望的响应对象的格式不是 JSON,你可以通过 responseType 属性来设定响应类型,比如:

代码语言:javascript复制
this.http.get("https://jsonplaceholder.typicode.com/todos/1", {
  responseType: "text"
}).subscribe(text => {
   console.log("Response: "   text);
});

需要注意的是除了支持 json 和 text 类型外,还支持 arraybuffer 和 blob 类型。

设置 Http Headers

代码语言:javascript复制
const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });
const headers = new HttpHeaders().set("token", "iloveangular");

ngOnInit() {
  this.todos$ = this.http
    .get<Todo[]>("https://jsonplaceholder.typicode.com/todos", {
        headers,
        params
     })
     .pipe(tap(console.log));
 }

发送 Put 请求

代码语言:javascript复制
const headers = new HttpHeaders().set(
  "Content-type",
  "application/json; charset=UTF-8"
);

updateFirstTodo() {
    this.http
      .put(
        "https://jsonplaceholder.typicode.com/todos/1",
        {
          userId: 1,
          id: 1,
          title: "delectus aut autem",
          completed: true
        },
        { headers }
      )
      .subscribe(
        val => {
          console.log("Put call successful value returned in body", val);
        },
        error => {
          console.log("Put call in error", error);
        },
        () => {
          console.log("The PUT observable is now completed.");
        }
      );
}

发送 Patch 请求

代码语言:javascript复制
const headers = new HttpHeaders().set(
  "Content-type",
  "application/json; charset=UTF-8"
);

patchFirstTodo() {
    this.http
      .patch(
        "https://jsonplaceholder.typicode.com/todos/1",
        {
          title: "learn angular 7"
        },
        { headers }
      )
      .subscribe(
        val => {
          console.log("Patch call successful value returned in body", val);
        },
        error => {
          console.log("Patch call in error", error);
        },
        () => {
          console.log("The Patch observable is now completed.");
        }
      );
}

发送 Delete 请求

代码语言:javascript复制
const headers = new HttpHeaders().set(
  "Content-type",
  "application/json; charset=UTF-8"
);

deleteFirstTodo() {
    this.http
      .delete("https://jsonplaceholder.typicode.com/todos/1", {
        headers
      })
      .subscribe(
        val => {
          console.log("Delete call successful value returned in body", val);
        },
        error => {
          console.log("Delete call in error", error);
        },
        () => {
          console.log("The Delete observable is now completed.");
        }
      );
}

发送 Post 请求

代码语言:javascript复制
const headers = new HttpHeaders().set(
  "Content-type",
  "application/json; charset=UTF-8"
);

createNewTodo() {
    this.http
      .post(
        "https://jsonplaceholder.typicode.com/todos",
        {
          userId: 1,
          title: "learn ionic 4",
          completed: false
        },
        { headers }
      )
      .subscribe(
        val => {
          console.log("Post call successful value returned in body", val);
        },
        error => {
          console.log("Post call in error", error);
        },
        () => {
          console.log("The Post observable is now completed.");
        }
      );
  }

并行发送多个 Http 请求

代码语言:javascript复制
parallelRequests() {
    const parallel$ = forkJoin(
      this.http.get("https://jsonplaceholder.typicode.com/users/1"),
      this.http.get("https://jsonplaceholder.typicode.com/todos/1")
    );

    parallel$.subscribe(values => {
      console.log("all values", values);
    });
 }

顺序发送 Http 请求

代码语言:javascript复制
sequentialRequests() {
    const sequence$ = this.http
      .get<Todo>("https://jsonplaceholder.typicode.com/todos/1")
      .pipe(
        switchMap(todo => {
          todo.title  = " - TEST ";
          return this.http.put("https://jsonplaceholder.typicode.com/todos/1", todo);
        })
      );

    sequence$.subscribe(val => {
      console.log("Put call successful value returned in body", val);
    });
}

获取顺序发送 Http 请求的结果

代码语言:javascript复制
sequentialRequests() {
    const sequence$ = this.http
      .get<Todo>("https://jsonplaceholder.typicode.com/todos/1")
      .pipe(
        switchMap(
          todo => {
            const newTitle = todo.title   " - TEST ";
            const newTodo = { ...todo, title: newTitle };
            return this.http.put(
              "https://jsonplaceholder.typicode.com/todos/1",
              newTodo
            );
          },
          (firstHTTPResult, secondHTTPResult) => [
            firstHTTPResult,
            secondHTTPResult
          ]
        )
      );

    sequence$.subscribe(val => {
      console.log("Put call successful value returned in body", val);
    });
}

请求异常处理

代码语言:javascript复制
import { of } from "rxjs";
import { catchError } from "rxjs/operators";

throwError() {
    this.http
      .get("https://jsonplaceholder.typicode.com/simulate-error")
      .pipe(
        catchError(error => {
          console.error("Error catched", error);
          return 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...")
      );
}

当发生异常时,控制台的输出结果:

代码语言:javascript复制
Error catched 
HttpErrorResponse {headers: HttpHeaders, status: 404, ...}
Value emitted successfully {description: "Error Value Emitted"}
HTTP Observable completed...

Http 拦截器

定义拦截器

auth.interceptor.ts

代码语言:javascript复制
import { Injectable } from "@angular/core";
import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor } from "@angular/common/http";

import { Observable } from "rxjs";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const clonedRequest = req.clone({
      headers: req.headers.set("X-CustomAuthHeader", "iloveangular")
    });
    console.log("new headers", clonedRequest.headers.keys());
    return next.handle(clonedRequest);
  }
}
应用拦截器
代码语言:javascript复制
import { AuthInterceptor } from "./interceptors/auth.interceptor";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Http 进度事件

代码语言:javascript复制
getData() {
   this.http
      .get("https://jsonplaceholder.typicode.com/todos", {
        observe: 'events',
        reportProgress: true
      })
      .subscribe((event: HttpEvent<any>) => {
        switch (event.type) {
          case HttpEventType.Sent:
            console.log("Request sent!");
            break;
          case HttpEventType.ResponseHeader:
            console.log("Response header received!");
            break;
          case HttpEventType.DownloadProgress:
            const kbLoaded = Math.round(event.loaded / 1024);
            console.log(`Download in progress! ${kbLoaded}Kb loaded`);
            break;
          case HttpEventType.Response:
            console.log("Done!", event.body);
        }
      });
}

以上代码成功运行后,在控制台会输出以下信息:

代码语言:javascript复制
Request sent!
Response header received!
Download in progress! 6Kb loaded
Download in progress! 24Kb loaded
Done!

总结

本文通过 jsonplaceholder 提供的 API,介绍了如何使用 HttpClientModule 模块中的 HttpClient 服务,发送 Get、Post、Delete 等请求,同时介绍了如何利用 RxJS 处理并行和顺序 Http 请求。

0 人点赞