Angular9 向服务器发送数据
除了从服务器获取数据外,HttpClient
还支持其它一些 HTTP 方法,比如 PUT
,POST
和 DELETE
,你可以用它们来修改远程数据。
本指南中的这个范例应用包括一个简化版本的《英雄指南》,它会获取英雄数据,并允许用户添加、删除和修改它们。 下面几节在 HeroesService
范例中展示了数据更新方法的一些例子。
发起一个 POST 请求
应用经常在提交表单时通过 POST
请求向服务器发送数据。 下面这个例子中,HeroesService
在向数据库添加英雄时发起了一个 HTTP POST
请求。
Path:"app/heroes/heroes.service.ts (addHero)" 。
/** POST: add a new hero to the database */
addHero (hero: Hero): Observable<Hero> {
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('addHero', hero))
);
}
HttpClient.post()
方法像 get()
一样也有类型参数,可以用它来指出你期望服务器返回特定类型的数据。该方法需要一个资源 URL 和两个额外的参数:
body
- 要在请求体中POST
过去的数据。
options
- 一个包含方法选项的对象,在这里,它用来指定必要的请求头。
该例子捕获了前面所指的错误。
HeroesComponent
通过订阅该服务方法返回的 Observable
发起了一次实际的 POST
操作。
Path:"app/heroes/heroes.component.ts (addHero)" 。
this.heroesService
.addHero(newHero)
.subscribe(hero => this.heroes.push(hero));
当服务器成功做出响应时,会带有这个新创建的英雄,然后该组件就会把这个英雄添加到正在显示的 heroes
列表中。
发起 DELETE 请求
该应用可以把英雄的 id
传给 HttpClient.delete
方法的请求 URL
来删除一个英雄。
Path:"app/heroes/heroes.service.ts (deleteHero)" 。
/** DELETE: delete the hero from the server */
deleteHero (id: number): Observable<{}> {
const url = `${this.heroesUrl}/${id}`; // DELETE api/heroes/42
return this.http.delete(url, httpOptions)
.pipe(
catchError(this.handleError('deleteHero'))
);
}
当 HeroesComponent
订阅了该服务方法返回的 Observable
时,就会发起一次实际的 DELETE
操作。
Path:"app/heroes/heroes.component.ts (deleteHero)" 。
this.heroesService
.deleteHero(hero.id)
.subscribe();
该组件不会等待删除操作的结果,所以它的 subscribe
(订阅)中没有回调函数。不过就算你不关心结果,也仍然要订阅它。调用 subscribe()
方法会执行这个可观察对象,这时才会真的发起 DELETE
请求。
注:
- 你必须调用
subscribe()
,否则什么都不会发生。仅仅调用HeroesService.deleteHero()
是不会发起DELETE
请求的。
// oops ... subscribe() is missing so nothing happens
this.heroesService.deleteHero(hero.id);
在调用方法返回的可观察对象的 subscribe()
方法之前,HttpClient
方法不会发起 HTTP 请求。这适用于 HttpClient
的所有方法。
AsyncPipe 会自动为你订阅(以及取消订阅)。
HttpClient
的所有方法返回的可观察对象都设计为冷的。 HTTP 请求的执行都是延期执行的,让你可以用 tap
和 catchError
这样的操作符来在实际执行 HTTP 请求之前,先对这个可观察对象进行扩展。
调用 subscribe(...) 会触发这个可观察对象的执行,并导致
HttpClient` 组合并把 HTTP 请求发给服务器。
你可以把这些可观察对象看做实际 HTTP 请求的蓝图。
实际上,每个
subscribe()
都会初始化此可观察对象的一次单独的、独立的执行。 订阅两次就会导致发起两个 HTTP 请求。
<br>const req = http.get<Heroes&('/api/heroes'); <br>// 0 requests made - .subscribe() not called. <br>req.subscribe(); <br>// 1 request made. <br>req.subscribe(); <br>// 2 requests made. <br>```
发起 PUT 请求
应用可以使用 HttpClient
服务发送 PUT
请求。下面的 HeroesService
示例(就像 POST
示例一样)用一个修改过的数据替换了该资源。
Path:"app/heroes/heroes.service.ts (updateHero)" 。
/** PUT: update the hero on the server. Returns the updated hero upon success. */
updateHero (hero: Hero): Observable<Hero> {
return this.http.put<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('updateHero', hero))
);
}
对于所有返回可观察对象的 HTTP 方法,调用者(HeroesComponent.update()
)必须 subscribe()
从 HttpClient.put()
返回的可观察对象,才会真的发起请求。
添加和更新请求头
很多服务器都需要额外的头来执行保存操作。 例如,服务器可能需要一个授权令牌,或者需要 Content-Type
头来显式声明请求体的 MIME
类型。
- 添加请求头。
HeroesService
在一个 httpOptions
对象中定义了这样的头,它们被传递给每个 HttpClient
的保存型方法。
Path:"app/heroes/heroes.service.ts (httpOptions)" 。
import { HttpHeaders } from '@angular/common/http';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'my-auth-token'
})
};
- 更新请求头。
你不能直接修改前面的选项对象中的 HttpHeaders
请求头,因为 HttpHeaders
类的实例是不可变对象。请改用 set()
方法,以返回当前实例应用了新更改之后的副本。
下面的例子演示了当旧令牌过期时,可以在发起下一个请求之前更新授权头。
httpOptions.headers =
httpOptions.headers.set('Authorization', 'my-new-auth-token');
更多建议: