一个 Web 应用通常会连接到远程服务器,使用基于HTTP 协议的 API 对数据进行操作,如检索、更新、创建和删除(CRUD)等。
本文通过一个实例来介绍如何在 Angular 应用中访问远程的 API.
模拟远程 API
很多时候,我们没有条件访问一个真正的后端 API 服务。例如:
- 在创建一个快速原型的时候
- 可用的 API 服务还没有交付
- 没有 VPN,无法连接远程服务器
我们可以创建一个完全运行在内存的 API 服务,模拟 Web 应用所需要的 API 服务。
- 安装必要的开发包。
npm install angular-in-memory-web-api@0.11.0 --save-dev
注意:angular-in-memory-web-api 的版本 0.11.0 适合于 Angular 10.
- 创建一个 Angular 服务,实现
InMemoryDbService interface
接口。
import { Injectable } from '@angular/core’;
import { InMemoryDbService } from "angular-in-memory-web-api”;
@Injectable({
providedIn: ‘root’
})
export class DataService implements InMemoryDbService {
constructor() { }
createDb() {
return {
books: [
{id: 1, name: '《三体》', price: 50.00},
{id: 2, name: '《黑暗森林》', price: 40.00},
{id: 3, name: '《死神永生》', price: 60.00},
{id: 4, name: '《超新星纪元》', price: 35.00}
]
}
}
}
Angular 服务必须实现 InMemoryDbService
接口的 createDb
方法,该方法会创建一个内存对象,表示一个数据库。
- 导入
HttpClientInMemoryWebApiModule
模块。
import { BrowserModule } from '@angular/platform-browser’;
import { NgModule } from '@angular/core’;
import { HttpClientInMemoryWebApiModule } from "angular-in-memory-web-api”;
import { AppComponent } from './app.component’;
import { DataService } from "./data.service”;
import { BooksModule } from './books/books.module’;
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientInMemoryWebApiModule.forRoot(DataService),
BooksModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
与导入 BrowserModule
模块不同,我们使用了 forRoot
方法,把 DataService
作为参数传入,这样可以确保只创建单一实例。
访问远程 API
接下来,我们使用 Angular 框架的内置 HTTP 客户端访问数据服务。
- 在
AppModule
模块中导入HttpClientModule
模块,使用HttpClientModule
模块中的服务处理异步的 HTTP 通信。
import { BrowserModule } from '@angular/platform-browser’;
import { NgModule } from '@angular/core’;
import { HttpClientInMemoryWebApiModule } from "angular-in-memory-web-api”;
import { HttpClientModule } from "@angular/common/http”;
import { AppComponent } from './app.component’;
import { DataService } from "./data.service”;
import { BooksModule } from './books/books.module’;
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
HttpClientInMemoryWebApiModule.forRoot(DataService),
BooksModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
在导入 HttpClientModule
模块时,要让 HttpClientModule
模块位于 HttpClientInMemoryWebApiModule
模块之前,使后者可以覆盖前者的默认行为。
- 在
HeroService
服务中注入HttpClient
.
import { Injectable } from '@angular/core’;
import { HttpClient } from "@angular/common/http”;
import { Book } from './book.model’;
@Injectable({
providedIn: ‘root’
})
export class BookService {
constructor(private http: HttpClient) { }
getBooks(): Book[] {
return [
{id: 1, name: '《三体》', price: 50.00},
{id: 2, name: '《黑暗森林》', price: 40.00},
{id: 3, name: '《死神永生》', price: 60.00},
{id: 4, name: '《超新星纪元》', price: 35.00}
];
}
}
- 修改
getBooks
方法,使其通过HttpClient
获取图书列表数据。
import { Injectable } from '@angular/core’;
import { HttpClient } from "@angular/common/http”;
import { Book } from './book.model’;
import { Observable } from ‘rxjs’;
@Injectable({
providedIn: ‘root’
})
export class BookService {
constructor(private http: HttpClient) { }
getBooks(): Observable<Book[]> {
return this.http.get<Book[]>('api/books’);
}
}
4.在 BookListComponent
类中,修改获取图书数据的逻辑。
import { Component, OnInit } from '@angular/core’;
import { Book } from '../book.model’;
import { BookService } from '../book.service’;
@Component({
selector: 'app-book-list’,
templateUrl: './book-list.component.html’,
styleUrls: ['./book-list.component.css’]
})
export class BookListComponent implements OnInit {
books: Book[];
constructor(private bookService: BookService) {
}
ngOnInit(): void {
this.getBooks();
}
private getBooks() {
this.bookService.getBooks().subscribe(books => this.books = books);
}
}
验证访问效果
在页面上图书列表时,会有一些延时,这是内存 Web API 模拟了真实的请求/响应的处理时间。我们可以在 HttpClientInMemoryWebApiModule
模块的 forRoot
方法配置 delay
属性,改变延时时长。