- Angular 教程
- Angular - 首页
- Angular - 概述
- Angular - 特性
- Angular - 优点与缺点
- Angular 基础
- Angular - 环境设置
- Angular - 第一个应用程序
- Angular - MVC 架构
- Angular 组件
- Angular - 组件
- Angular - 组件生命周期
- Angular - 视图封装
- Angular - 组件交互
- Angular - 组件样式
- Angular - 嵌套组件
- Angular - 内容投影
- Angular - 动态组件
- Angular - 元素
- Angular 模板
- Angular - 模板
- Angular - 文本插值
- Angular - 模板语句
- Angular - 模板中的变量
- Angular - SVG 作为模板
- Angular 绑定
- Angular - 绑定及其类型
- Angular - 数据绑定
- Angular - 事件绑定
- Angular - 属性绑定
- Angular - 属性绑定
- Angular - 类和样式绑定
- Angular 指令
- Angular - 指令
- Angular - 内置指令
- Angular 管道
- Angular - 管道
- Angular - 使用管道转换数据
- Angular 依赖注入
- Angular - 依赖注入
- Angular HTTP 客户端编程
- Angular - 服务
- Angular - HTTP 客户端
- Angular - 请求
- Angular - 响应
- Angular - 获取
- Angular - PUT
- Angular - DELETE
- Angular - JSON-P
- Angular - 使用 HTTP 进行 CRUD 操作
- Angular 路由
- Angular - 路由
- Angular - 导航
- Angular - Angular Material
- Angular 动画
- Angular - 动画
- Angular 表单
- Angular - 表单
- Angular - 表单验证
- Angular Service Workers 和 PWA
- Angular - Service Workers 和 PWA
- Angular 测试
- Angular - 测试概述
- Angular NgModules
- Angular - 模块简介
- Angular 高级
- Angular - 身份验证和授权
- Angular - 国际化
- Angular - 可访问性
- Angular - Web Workers
- Angular - 服务器端渲染
- Angular - Ivy 编译器
- Angular - 使用 Bazel 构建
- Angular - 向后兼容性
- Angular - 响应式编程
- Angular - 在指令和组件之间共享数据
- Angular 工具
- Angular - CLI
- Angular 杂项
- Angular - 第三方控件
- Angular - 配置
- Angular - 显示数据
- Angular - 装饰器和元数据
- Angular - 基本示例
- Angular - 错误处理
- Angular - 测试和构建项目
- Angular - 生命周期钩子
- Angular - 用户输入
- Angular - 有什么新功能?
- Angular 有用资源
- Angular - 快速指南
- Angular - 有用资源
- Angular - 讨论
Angular - 请求
Http 请求
在 Http 协议中,请求是指客户端应用程序启动与服务器通信的过程。在本章中,我们将了解如何在 Angular 框架中向服务器发送请求,以及请求阶段可用的选项。
设置服务器应用程序
为了实现 HTTP 客户端-服务器通信,我们需要设置一个 Web 应用程序,并需要公开一组 Web API。可以从客户端请求 Web API。让我们创建一个示例服务器应用程序 Expense API App,为费用提供 CRUD REST API。
步骤 1:转到您喜欢的 workspace,如下所示:
cd /go/to/your/favorite/workspace
步骤 2:创建一个新文件夹 expense-rest-api 并移动到该文件夹中
mkdir expense-rest-api && cd expense-rest-api
步骤 3:使用 npm 命令提供的 init 子命令创建一个新应用程序,如下所示:
npm init
上述命令会询问一些问题,并使用默认答案回答所有问题。
步骤 4:安装 express 和 cors 包以创建基于节点的 Web 应用程序。
npm install express cors --save
步骤 5:安装 sqlite 包以将费用存储在基于 sqlite 的数据库中
npm install sqlite3 --save
步骤 6:创建一个新文件 sqlitedb.js 并添加以下代码以使用费用表和示例费用条目初始化数据库。费用表将用于存储费用项目
var sqlite3 = require('sqlite3').verbose()
const DBSOURCE = "expensedb.sqlite"
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
console.error(err.message)
throw err
}else{
console.log('Connected to the SQLite database.')
db.run(`CREATE TABLE IF NOT EXISTS expense (
id INTEGER PRIMARY KEY AUTOINCREMENT,
item text,
amount real,
category text,
location text,
spendOn text,
createdOn text
)`,
(err) => {
if (err) {
console.log(err);
}else{
var insert = 'INSERT INTO expense (item, amount, category, location, spendOn, createdOn) VALUES (?,?,?,?,?,?)'
db.run(insert, ['Pizza', 10, 'Food', 'KFC', '2020-05-26 10:10', '2020-05-26 10:10'])
db.run(insert, ['Pizza', 9, 'Food', 'Mcdonald', '2020-05-28 11:10', '2020-05-28 11:10'])
db.run(insert, ['Pizza', 12, 'Food', 'Mcdonald', '2020-05-29 09:22', '2020-05-29 09:22'])
db.run(insert, ['Pizza', 15, 'Food', 'KFC', '2020-06-06 16:18', '2020-06-06 16:18'])
db.run(insert, ['Pizza', 14, 'Food', 'Mcdonald', '2020-06-01 18:14', '2020-05-01 18:14'])
}
}
);
}
});
module.exports = db
步骤 7:打开 index.js 并更新以下代码:
var express = require("express")
var cors = require('cors')
var db = require("./sqlitedb.js")
var app = express()
app.use(cors());
var bodyParser = require("body-parser");
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
var HTTP_PORT = 8000
app.listen(HTTP_PORT, () => {
console.log("Server running on port %PORT%".replace("%PORT%", HTTP_PORT))
});
app.get("/", (req, res, next) => {
res.json({ "message": "Ok" })
});
app.get("/api/expense", (req, res, next) => {
var sql = "select * from expense"
var params = []
db.all(sql, params, (err, rows) => {
if (err) {
res.status(400).json({ "error": err.message });
return;
}
res.json(rows)
});
});
app.get("/api/jsonp/expense", (req, res, next) => {
var sql = "select * from expense"
var params = []
db.all(sql, params, (err, rows) => {
if (err) {
res.status(400).json({ "error": err.message });
return;
}
res.jsonp(rows)
});
});
app.get("/api/expense/:id", (req, res, next) => {
var sql = "select * from expense where id = ?"
var params = [req.params.id]
db.get(sql, params, (err, row) => {
if (err) {
res.status(400).json({ "error": err.message });
return;
}
res.json(row)
});
});
app.post("/api/expense/", (req, res, next) => {
var errors = []
if (!req.body.item) {
errors.push("No item specified");
}
var data = {
item: req.body.item,
amount: req.body.amount,
category: req.body.category,
location: req.body.location,
spendOn: req.body.spendOn,
createdOn: req.body.createdOn,
}
var sql = 'INSERT INTO expense (item, amount, category, location, spendOn, createdOn) VALUES (?,?,?,?,?,?)'
var params = [data.item, data.amount, data.category, data.location, data.spendOn, data.createdOn]
db.run(sql, params, function (err, result) {
if (err) {
res.status(400).json({ "error": err.message })
return;
}
data.id = this.lastID;
res.json(data);
});
})
app.post("/api/expense/:id/update_amount", (req, res, next) => {
var errors = []
if (!req.params.id) {
errors.push("No item specified");
}
var sql = 'UPDATE expense SET amount = ? WHERE id = ?'
var params = [req.body.amount, req.params.id]
db.run(sql, params, function (err, result) {
if (err) {
res.status(400).json({ "error": err.message })
return;
}
res.json({ id: req.params.id, amount: req.body.amount });
});
})
app.put("/api/expense/:id", (req, res, next) => {
if (req.params.id == null) {
res.status(400).json({ "error": "Resource (Expense) Id is not send." })
return
}
var data = {
id: req.params.id,
item: req.body.item,
amount: req.body.amount,
category: req.body.category,
location: req.body.location,
spendOn: req.body.spendOn
}
var sql = 'SELECT count(*) AS cnt FROM expense WHERE id = ?'
var params = [data.id]
db.get(sql, params, function (err, result) {
if (err) {
res.status(400).json({ "error": err.message })
return;
}
if (result.cnt == 0) {
var sql = 'INSERT INTO expense (id, item, amount, category, location, spendOn, createdOn) VALUES (?, ?,?,?,?,?,?)'
var params = [data.id, data.item, data.amount, data.category, data.location, data.spendOn, data.createdOn]
db.run(sql, params, function (err, result) {
if (err) {
res.status(400).json({ "error": err.message })
return;
}
console.log(result)
res.json(data);
});
} else {
db.run(
`UPDATE expense SET
item = ?,
amount = ?,
category = ?,
location = ?,
spendOn = ?
WHERE id = ?`,
[data.item, data.amount, data.category, data.location, data.spendOn, data.id],
function (err, result) {
if (err) {
console.log(err);
res.status(400).json({ "error": res.message })
return;
}
res.json(data)
});
}
});
})
app.delete("/api/expense/:id", (req, res, next) => {
db.run(
'DELETE FROM expense WHERE id = ?',
req.params.id,
function (err, result) {
if (err) {
res.status(400).json({ "error": res.message })
return;
}
res.json({ "message": "deleted", changes: this.changes })
});
})
app.use(function (req, res) {
res.status(404);
});
这里,代码将创建以下六个提到的 REST API 端点
/ 端点返回一个 OK 消息以确保应用程序正常工作
/api/expense 端点返回数据库中所有可用的费用项目
/api/jsonp/expense 端点以 jsonp 格式返回数据库中所有可用的费用项目
/api/expense/:id 端点根据费用条目 ID 返回费用条目
/api/expense/:id 端点使用 put 方法将根据费用条目 ID 更新费用条目
/api/expense 端点使用 post 方法将新的费用条目添加到数据库中
/api/expense/:id/update_amount 端点使用 post 方法将更新 URL 中指定的费用条目的金额
/api/expense/:id 端点使用 delete 方法将根据费用条目 ID 删除费用条目
步骤 8:运行应用程序,如下所示:
node index.js
步骤 9:要测试应用程序并确保它正常工作,请打开浏览器并转到https://:8000/。如果应用程序正常工作,它应该返回以下消息。
{
"message": "Ok"
}
设置 HttpClient 服务
在开始 http 请求之前,我们需要在应用程序中正确设置 HttpClient 服务。Angular 为 http 通信提供了一个单独的模块 HttpClientModule,其中包含 HttpClient 服务。要使用 HttpClient 服务,应将 HttpClientModule 导入到应用程序中,无论是在应用程序的根/模块配置部分。
步骤 1:要在独立应用程序(组件)中导入 HttpClientModule,请在根配置中使用 importProvidersFrom 方法,如下所示:
import { bootstrapApplication } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { importProvidersFrom } from '@angular/core';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(HttpClientModule),
]
});
这里,
importProvidersFrom 方法是从 angular core 包导入的。它导入 HttpClientModule 中包含的所有提供程序
步骤 2:要在 Web 应用程序中导入 HttpClientModule,请在根/相应模块文件中 imports 数组中导入 HttpClientModule 模块,如下所示:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
导入 http 模块将在 Angular 依赖注入设置中包含 HttpClient 服务,以便可以根据需要将 HttpClient 注入到任何 Angular 组件中,如下所示:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class MyService {
constructor(private http: HttpClient) { }
}
请求/响应工作流程
HttpClient 提供了几种方法来启动 http 请求。基本上,所有方法都返回一个带有可选类型变量的可观察对象 (Observable<T>)。可以订阅可观察对象以启动请求。一旦订阅了可观察对象,它就会启动请求并将其传递给一系列已注册的拦截器,最后到达服务器。然后,它从服务器接收响应并将其发布到已订阅的函数。
请求的工作流程如下:
用户创建一个新的 HttpClient 实例,例如通过组件的构造函数创建 http。
constructor(private http: HttpClient) { }
用户通过传递资源信息来调用任何一个 HttpClient 方法,例如 request()。
let req = this.http.request(<action>, <url>, <body>, <option>)
request() 方法将使用给定的资源信息创建一个可观察对象,例如 req。
let req = this.http.request(<action>, <url>, <body>, <option>)
用户将使用 subscribe() 方法将回调函数订阅到可观察对象。
req.subscribe((data) => console.log(data));
一旦用户订阅了 Observable,它就会将请求传递给已注册的拦截器,其顺序与拦截器的注册顺序相同。
一旦请求通过所有已注册的拦截器,Observable 将向服务器发送请求。
Observable 等待服务器响应,一旦从服务器接收到响应,它就会将响应返回给已订阅的函数
已订阅的函数将执行必要的业务逻辑并将输出设置为组件的变量。
组件将使用 HttpClient 的输出呈现其模板。
一个示例请求如下:
let req = this.http.request('GET', 'https://:8000/api/expense/1')
req.subscribe(data => this.myexpense = data);
这里,
this.http 是 HttpClient 实例
request() 是用于创建可观察对象的方法,当订阅时,它会启动请求。
subscribe() 是用于订阅返回的可观察对象并随后启动请求和获取响应的方法。
最后,subscribe 方法的参数是用于获取实际响应主体内容的回调函数。
HttpClient 参数
HttpClient 方法支持的参数如下:
资源 URI - 它基本上是表示资源的 URL/端点。
请求正文 - 它基本上是与请求一起发送到服务器的数据。数据可以是查询字符串格式或 json 格式。
请求选项 - 它基本上是与请求一起发送的所有其他数据。它包含查询字符串、标题、cookie 等。
资源 URI
所有方法都接受 url/端点作为参数之一。它表示要从服务器获取的资源。在我们的示例应用程序中,url 以 https://:8000/ 开头,一个可能的选项是 https://:8000/api/expenses。此端点将从服务器获取所有费用并以 json 格式将其发送回客户端。
请求正文
所有方法都接受 body 作为参数之一。body 参数在某些方法中是可选的。请求的正文将支持不同的格式,它将在请求的标头 Content-Type 中使用 MIME 类型指定。最常见的数据类型如下:
表单数据。MIME 类型为 application/x-www-form-urlencoded
带有上传的表单数据。MIME 类型为 multipart/form-data
纯文本。MIME 类型为 text/plain
JSON。MIME 类型为 application/json
HttpParams 类
表单数据可以使用 Angular 提供的 HttpParams 类创建。HttpParams 以查询字符串格式接受数据(键/值作为 key=value,每个键/值用 & 分隔)。它具有将一个或多个参数作为序列添加的方法,方法是将方法链接在一起。所有方法都创建实例的副本,并在复制的实例中添加/删除参数(键/值对),并将其返回。
HttpParams 构造函数的签名如下:
constructor(options: HttpParamsOptions = {} as HttpParamsOptions)
其中,
HttpParamsOptions 对象可以通过以下属性创建:
- fromString?: string
- fromObject?: {…}
使用构造函数创建 HttpParams 对象的示例代码如下:
/* using fromString option */
let httpParams = new HttpParams( { fromString: 'a=b*b=c' } )
/* using fromObject option */
let httpParams = new HttpParams( { fromObject: { a: "b", c: "d" } )
HttpParams 支持的方法如下:
set(): 接收一个参数和值。添加一个具有给定值的新参数。
delete(): 接收一个参数。删除给定的参数。
has(): 接收一个参数。根据给定参数是否存在返回 true/false。
keys(): 不接收任何参数。返回所有参数。
get(): 接收一个参数。返回给定参数的第一个值。
getAll(): 接收一个参数。返回给定参数的所有值。
append(): 接收一个参数。将值添加到给定参数。
appendAll(): 接收一个包含多个参数的对象。将值添加到所有参数。
toString(): 不接收任何参数。以查询字符串格式返回对象。
创建 HttpParams 对象的示例代码如下:
let formData = new HttpParams();
formData = formData
.set('item', 'Modified')
.set('amount', 25);
console.log(formData.toString()) // item=Modified&amount=25
请求选项
无论使用何种方法,options 都是所有方法都接受的一个通用参数,用于表示请求选项。options 是一个包含标准请求数据的 JavaScript 对象(或哈希表)。options 可以包含以下条目,并表示请求和响应的不同方面。
- observe
- responseType
- headers
- params
- context
- reportProgress
- withCredentials
- transferCache
让我们在接下来的章节中逐一学习。
observe
observe 用于指定在服务器通信期间需要观察响应的哪一部分,并将数据发送回订阅函数。根据 observe 选项,将返回完整的响应或部分响应。可能的值有 events、body 和 response。
events
events 用于返回服务器响应流中触发的事件。它将响应作为 Observable<HttpEvent> 类型返回。这里,R 是要返回的实际数据(响应体)的类型。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'events',
responseType : 'json'
});
这里,
json 是用于解释响应体的格式。
Expense 是用于转换和返回响应体的类型。否则,它将以通用的 JavaScript 对象形式返回响应体。
response
response 用于返回服务器的完整响应。它将响应作为 Observable<HttpResponse> 类型返回。这里,R 是要返回的实际数据(响应体)的类型。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'response',
responseType : 'json'
});
这里,
json 是用于解释响应体的格式。
expense 是用于转换和返回响应体的类型。否则,它将以通用的 JavaScript 对象形式返回响应体。
body
body 用于仅返回服务器响应的正文内容。它将响应作为 Observable 类型返回,这里,R 是要返回的实际数据(响应体)的类型。
let req = this.http.request<Expense>( 'GET','https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json'
});
这里,
json 是用于解释响应体的格式。
Expense 是用于转换和返回响应体的类型。否则,它将以通用的 JavaScript 对象形式返回响应体。
responseType
responseType 用于解释响应体。它可以具有以下四个可能的值:
- arraybuffer
- blob
- text
- json
让我们逐一了解这些选项。
arraybuffer
arraybuffer 用于将响应体解释为通用的原始二进制数据缓冲区并返回 Observable。它可用于流式传输音频/视频内容。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'arraybuffer'
});
body
blob 用于将响应体解释为二进制格式并返回 Observable。它可用于下载大型文件。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'blob'
});
text
text 用于将响应体解释为纯文本格式并返回 Observable。它可用于表示基于文本的数据。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'text'
});
json
json 用于将响应体解释为 json 格式并返回 Observable,其中 R 是请求的数据类型 (Expense)。它可用于以 json 格式表示结果。通过在方法中指定类型变量 (R),可以将其进一步编码为任何类型,如下所示:
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json'
});
根据 observe 和 responseType,Httpclient 将返回具有不同类型变量的 Observable。让我们检查 observe 和 responseType 的一些组合以更好地理解这个概念。
-
observe => body 和 responseType => json
返回 Observable。R 表示类型变量。
-
observe => response 和 responseType => json
返回 Observable<HttpResponse>。R 表示类型变量并编码响应体。
-
observe => events 和 responseType => json
返回 Observable<HttpEvent>。R 表示类型变量并编码响应体。
-
observe => events 和 responseType => arraybuffer
返回 Observable<HttpEvent>。响应体被编码为 ArrayBuffer。
-
observe => response 和 responseType => blob
返回 Observable<HttpEvent>。响应体被编码为 ArrayBuffer。
-
observe => response 和 responseType => text
返回 Observable<HttpResponse>。响应体被编码为 ArrayBuffer。
我们可以根据需要组合 observe 和 responseType 来创建更多组合。
headers
headers 用于指定 HTTP 标头。它可以包含标准的 http 标头作为键/值对,也可以使用 HttpHeaders 类对数据进行编码。一个键/值对的示例标头如下所示:
{ 'Content-type': 'application/json' }
它指定请求内容类型为 json。
Angular 提供了一个特殊的类 HttpHeaders 来组合标头详细信息。它接受匿名对象作为标头信息并初始化它。它具有方法(set()、append()、delete() 等),可以通过将方法链接在一起,依次添加/删除一个或多个标头。所有方法都会创建实例的副本,并在副本中添加/删除标头信息,并返回它。
let httpHeaders = new HttpHeaders( { 'Content-Type': 'application/json' })
httpHeaders = httpHeaders
.set('Accept-Language', 'en-US,en;q=0.5')
.set('Accept-Encoding', 'gzip, deflate, br');
let options = { 'headers': httpHeaders }
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', options );
req.subscribe( (data: Expense) => this.myexpense = data );
这里,
httpHeaders 是一个用于封装要发送到服务器的 HTTP 标头信息的 对象。它是使用 HttpHeaders 类创建的。
options 是一个包含标头信息的增强对象。
HttpHeaders 支持的方法如下:
set(): 接收一个标头和值。添加一个具有给定值的新标头。
delete(): 接收一个标头。删除给定的参数。
has(): 接收一个参数。根据给定标头是否存在返回 true/false。
keys(): 不接收任何参数。返回所有参数。
get(): 接收一个参数。返回给定参数的第一个值。
getAll(): 接收一个标头。返回给定参数的所有值。
append(): 接收一个参数。将值添加到给定标头。
appendAll(): 接收一个包含多个参数的对象。将值添加到所有标头。
toString(): 不接收任何参数。以查询字符串格式返回对象。
params
params 允许使用 HttpParams 类设置查询字符串。请查看请求正文部分以了解有关 HttpParams 类的更多信息。
创建 HttpParams 对象并在请求中设置它的示例代码如下:
let formData = new HttpParams();
formData = formData
.set('item', 'Modified')
.set('amount', 25);
console.log(formData.toString()) // item=Modified&amount=25
let req = this.http.request<Expense>('GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json',
params: formData
});
context
context 用于以类型安全的方式并避免键冲突的方式发送任意键/值对。它用作拦截器的信息源,拦截器充当客户端和服务器之间的中间件。Angular 提供了一个特殊的类 HttpContext 来编码上下文信息。一个上下文示例如下所示:
// create a key using HttpContextToken
export const IS_AUTH_ENABLED = new HttpContextToken<boolean>(() => false);
// set data for the context
let authContext = new HttpContext().set(IS_AUTH_ENABLED, true)
let req = this.http.request<Expense>('GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json',
context: authContext
});
这里,
HttpContextToken 类用于创建上下文的键。它可以选择指定值类型。
IS_AUTH_ENABLED 是键,其类型为布尔值。
IS_AUTH_ENABLED 设置为 true。
我们可以使用 get() 方法通过传递令牌来获取上下文值,如下所示:
let contextValue = req.context.get<boolean>(IS_AUTH_ENABLED) // true
reportProgress
reportProgress 用于指定是否从服务器获取请求(通信)的进度。它可用于显示通过 Web API 上传大型文件的进度。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'events',
responseType : 'json',
reportProgress: true
});
withCredentials
withCredential 用于指定是否应将请求与传出凭据(cookie)一起发送。它接受布尔值。
this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json'
withCredentials: true
});
transferCache
transferCache 用于指定是否应缓存请求。它接受布尔值或 HttpTransferCacheOptions 值。HttpTransferCacheOptions 用于编码动态逻辑,以根据自定义筛选器函数筛选要缓存的请求并覆盖默认缓存行为。
let req = this.http.request<Expense>( 'GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json',
transferCache: true
});
HttpClient 方法
HttpClient 类提供的用于客户端-服务器通信的方法如下:
- request()
- head()
- get()
- post()
- put()
- patch()
- delete()
- jsonp()
- options()
我们将在本章中学习通用 request() 方法,并在后续章节中学习其他方法。
request() 方法
request() 是一个通用方法,用于使用所有可能的 HTTP 动词(如 get、post、patch 等)向服务器发送请求。它有许多重载。让我们检查两个主要的重载函数,一个使用泛型选项,另一个使用 HttpRequest 对象。
泛型选项 - 接收 url、http 动词、正文内容和 options 对象。
HttpRequest 选项 - 接收 HttpRequest 对象。
HttpRequest 选项
Angular 提供了一个类 HttpRequest 来表示完整的 http 请求。它具有内置选项,可以包含 url、HTTP 方法/动词、响应类型、标头、参数等。
一个 HttpRequest 对象示例如下所示:
var httpRequest = new HttpRequest<Expense>('GET', 'https://:8000/api/expense/1', {
responseType : 'json'
});
这里,
this.http 是 HttpClient 实例。
GET 方法用作 HTTP 动词。
端点 (https:///api/expense/1) 将从服务器返回 id 等于 1 的费用。
responseType 设置为 json。这将以 json 格式返回响应的正文。
上面的示例请求对象可以像下面这样使用,以将请求发送到服务器:
var req = this.http.request<Expense>(httpRequest);
req.subscribe(data : HttpEvent<Expense> => {
this.myexpense = (data as HttpResponse<Expense>).body as Expense;
}
这里,
request() 返回 HttpEvent,它是多种类型的联合,如下所示:
type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;
由于我们将 responseType 设置为 json 并将 Expense 设置为要返回的对象,因此 observable 将在正文中返回 HttpResponse<Expense>。因此,我们将返回的数据对象转换为 HttpResponse<Expense> 对象,然后从 body 属性获取费用。
泛型选项
它按给定顺序接收四个参数,如下所示:
- HTTP 方法/动词
- url
- body(可选)
- options
一个示例请求如下:
let req = this.http.request<Expense>('GET', 'https://:8000/api/expense/1', {
observe: 'body',
responseType : 'json',
});
req.subscribe(data => { this.myexpense = data });
工作示例
让我们创建一个 Angular 工作示例,以使用 HttpClient 服务类和 HttpRequest 选项从服务器获取所有费用项目。
步骤 1:通过运行 ng new 命令创建一个新的 Angular 应用程序,如下所示:
ng new my-http-app
启用 Angular 路由和 CSS,如下所示:
? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
步骤 2:通过在模块配置文件 (app.module.ts) 中导入 HttpClientModule 来启用应用程序中的 http 通信。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
这里,
从 @angular/common/http 模块导入 HttpClientModule。
将 HttpClientModule 添加到 @NgModule 配置的 imports 部分。
步骤 3:创建一个新的接口 Expense 来表示我们的费用项目。
interface Expense {
id: Number,
item: String,
amount: Number,
category: String,
location: String,
spendOn: Date
}
export default Expense;
步骤 4:创建一个新的组件 ListExpenses 来显示来自服务器的费用项目。
ng generate component ListExpenses
它将创建如下所示的组件:
CREATE src/app/list-expenses/list-expenses.component.css (0 bytes) CREATE src/app/list-expenses/list-expenses.component.html (28 bytes) CREATE src/app/list-expenses/list-expenses.component.spec.ts (602 bytes) CREATE src/app/list-expenses/list-expenses.component.ts (229 bytes) UPDATE src/app/app.module.ts (581 bytes)
步骤 5:将我们的新组件包含到 App 根组件的视图 app.component.html 中,如下所示:
<app-list-expenses></app-list-expenses> <router-outlet></router-outlet>
步骤 6:通过构造函数将 HttpClient 注入到 ListExpenses 组件中,如下所示:
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-list-expenses',
templateUrl: './list-expenses.component.html',
styleUrls: ['./list-expenses.component.css']
})
export class ListExpensesComponent {
constructor(private http: HttpClient) { }
}
步骤 7:实现 OnInit 生命周期钩子,以便在 ListExpenses 组件初始化后向服务器请求费用。
export class ListExpensesComponent implements OnInit{
constructor(private http: HttpClient) { }
ngOnInit(): void {
}
}
步骤 8:创建一个局部变量 expenses 来保存来自服务器的费用。
export class ListExpensesComponent implements OnInit{
expenses: Expense[] = [];
constructor(private http: HttpClient) { }
ngOnInit(): void {
}
}
步骤9:创建一个HttpRequest对象并设置费用端点的URL。
export class ListExpensesComponent implements OnInit{
expenses: Expense[] = [];
constructor(private http: HttpClient) { }
ngOnInit(): void {
let req = new HttpRequest(
'GET',
'https://:8000/api/expense',{
responseType: 'json'
}
)
}
}
这里,
将GET设置为我们端点的HTTP方法
将https://:8000/api/expense设置为我们端点的URL
将json设置为responseType。这将把响应体解析为JSON格式。
步骤10:通过传递HttpRequest对象调用this.http(HttpClient实例)对象的request方法,并从服务器获取费用对象。然后,将费用设置到我们的本地变量expenses中。
export class ListExpensesComponent implements OnInit{
expenses: Expense[] = [];
constructor(private http: HttpClient) { }
ngOnInit(): void {
let req = new HttpRequest(
'GET',
'https://:8000/api/expense',{
responseType: 'json'
}
)
this.http.request<Expense[]>(req)
.subscribe((data : HttpEvent<Expense[]> )=> {
this.expenses = (data as HttpResponse<Expense[]>).body as Expense[]
console.log(this.expenses)
})
}
}
这里,
将Expense[]设置为服务器返回的对象的类型。服务器将在其主体中以JSON格式发送费用对象的数组。
订阅请求(this.http.request)对象。然后将订阅的数据解析为费用对象的数组,并将其设置为本地费用变量(this.expenses)
步骤11:ListExpensesComponent的完整代码如下:
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpRequest, HttpResponse, HttpEvent } from '@angular/common/http';
import Expense from '../Expense';
@Component({
selector: 'app-list-expenses',
templateUrl: './list-expenses.component.html',
styleUrls: ['./list-expenses.component.css']
})
export class ListExpensesComponent implements OnInit{
expenses: Expense[] = [];
constructor(private http: HttpClient) { }
ngOnInit(): void {
let req = new HttpRequest(
'GET',
'https://:8000/api/expense',{
responseType: 'json'
}
)
this.http.request<Expense[]>(req)
.subscribe((data : HttpEvent<Expense[]> )=> {
this.expenses = (data as HttpResponse<Expense[]>).body as Expense[]
console.log(this.expenses)
})
}
}
步骤12:接下来,从组件中获取费用对象,并在我们的组件模板页面(list-expenses.component.html)中渲染它。
<div><h3>Expenses</h3></div>
<ul>
<li *ngFor="let expense of expenses">
{{expense.item}} @ {{expense.location}} for {{expense.amount}} USD on {{expense.spendOn | date:'shortDate' }}
</li>
</ul>
步骤13:最后,使用以下命令运行应用程序:
ng serve
步骤14:打开浏览器并导航到https://:4200/ URL,并检查输出。
在这里,输出显示我们的费用作为项目列表。
步骤15:让我们通过将HttpRequest选项更改为通用选项来修改上述示例应用程序。
步骤16:按如下所示更改ngOnInit方法:
ngOnInit(): void {
this.http.request<Expense[]>('GET', 'https://:8000/api/expense', {
observe : 'body',
responseType : 'json'
})
.subscribe( data => {
this.expenses = data as Expense[]
console.log(this.expenses)
})
}
这里,
删除了HttpRequest对象
通过合并通用选项更改了request方法的参数
在第三个参数中设置observe选项为body。这将解析主体并仅返回主体,而不是整个响应。
更改了subscribe()方法,并将返回的数据设置为费用的数组(Expense[])
步骤17:运行应用程序并确认输出。输出与上述示例相同。
结论
Angular 提供了一种通过HttpClient和HttpRequest对象请求服务器的简单方法。request()方法是一个通用方法,用于支持所有HTTP动词,如GET、POST、PUT、DELETE等。我们将在后续章节中学习更多针对特定HTTP动词的方法。