fetch API
是原生 JavaScript 提供的一个概念,主要用来与 Web 服务器进行交互。 我们如何在
async
和
await
中使用
fetch
呢? 以及如何将它与 TypeScript 结合在一起使用呢? 让我们开始探索吧……
创建一个简单的请求
ES 最新特新已支持在
顶层 await
,因此,我们只需要把
await
关键字放在
fetch
函数前面即可
const response = await fetch("https://jsonplaceholder.typicode.com/todos");
为了获得响应的内容,我们需要调用 response 的json
方法
const body = await response.json();
注意: 我们使用了await
关键字,因为response.json()
是异步的。
创建一个工具函数
我们创建一个可以被调用的请求工具函数-http,该函数将上面两行代码结合起来并返回响应内容
export async function http(request: RequestInfo): Promise<any> {
const response = await fetch(request);
const body = await response.json();
return body;
// example consuming code
const data = await http("https://jsonplaceholder.typicode.com/todos");
很棒! 我们通过调用请求工具-http
函数,一行代码就实现了数据的请求和响应!
定义响应数据的类型
在前面的例子中,我们将响应数据的类型设置为Promise<any>
,接下来我们把此类型再精确一下
export async function http<T>(request: RequestInfo): Promise<T> {
const response = await fetch(request);
const body = await response.json();
return body;
// example consuming code
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
const data = await http<Todo[]>("https://jsonplaceholder.typicode.com/todos");
现在,我们的http
函数接收一个泛型参数作为响应数据的类型.
泛型就可以实现我们的场景:
一个函数可以支持多种数据类型
并且不预先确定数据类型,具体的类型在使用的时候才能确认
在上面的代码中,我们的data
这个数据的真实类型其实Todo[]
较完善的响应类型定义
interface HttpResponse<T> extends Response {
parsedBody?: T;
export async function http<T>(request: RequestInfo): Promise<HttpResponse<T>> {
const response: HttpResponse<T> = await fetch(request);
response.parsedBody = await response.json();
return response;
// example consuming code
const response = await http<Todo[]>(
"https://jsonplaceholder.typicode.com/todos",
因此,我们使用extends
继承了 TS 中Response
类型来解析的响应内容。 在整个响应被返回之前,我们在响应上设置parsedBody
属性。 现在,我们上面的代码中获得了完整的响应。
捕获 http 工具中的错误
现在,让我们优化http
函数来处理 HTTP 请求中发生错误的情况。 如果请求失败,我们可以使用response
对象中的ok
属性进行判断
export async function http<T>(request: RequestInfo): Promise<HttpResponse<T>> {
const response: HttpResponse<T> = await fetch(request);
try {
// 如果没有响应内容,这里可能会报错
response.parsedBody = await response.json();
} catch (ex) {}
if (!response.ok) {
throw new Error(response.statusText);
return response;
// 示例
let response: HttpResponse<Todo[]>;
try {
response = await http<Todo[]>("https://jsonplaceholder.typicode.com/todosX");
console.log("response", response);
} catch (response) {
console.log("Error", response);
使用try ... catch
将错误 ❎ 抛出到外部
HTTP 中的请求方法封装
通过调用http
函数,我们可以如何使用除GET
之外的 HTTP 方法,如下所示
const response = await http<{
id: number;
new Request("https://jsonplaceholder.typicode.com/posts", {
method: "post",
body: JSON.stringify({
title: "my post",
body: "some content",
我们为期望的响应正文类型传递了一个内联类型{id:number},即,我们希望将新帖子的 ID 返回给我们。
并且注意,我们必须使用JSON.stringify
将 post 对象转换为字符串。
比较麻烦是不是,但我们可以通过为不同的 HTTP 方法提供特定的功能,让使用者的的工作变得更轻松:
export async function get<T>(
path: string,
args: RequestInit = { method: "get" }
): Promise<HttpResponse<T>> {
return await http<T>(new Request(path, args));
export async function post<T>(
path: string,
body: any,
args: RequestInit = { method: "post", body: JSON.stringify(body) }
): Promise<HttpResponse<T>> {
return await http<T>(new Request(path, args));
export async function put<T>(
path: string,
body: any,
args: RequestInit = { method: "put", body: JSON.stringify(body) }
): Promise<HttpResponse<T>> {
return await http<T>(new Request(path, args));
// example consuming code
const response = await post<{ id: number }>(
"https://jsonplaceholder.typicode.com/posts",
{ title: "my post", body: "some content" }
因此,这些函数调用基本的 http 函数,但设置了正确的 HTTP 方法并为我们序列化了请求体。
现在,使用 HTTP 请求更加简单了!
借助一些不错的包装,我们可以轻松地将fetch
,await
,async
,TypeScript 一起使用。 我们还对 HTTP 请求错误进行了抛出,这可以说是 HTTP 库的一种较常见的行为。 最后封装了针对 HTTP 请求方法的函数,使与 Web 服务进行交互变得非常容易。
参考文档:
www.carlrippon.com/fetch-with-…
当然!还有许多请求过程中的问题需要判断和处!咱们后续再更新,敬请期待!
你觉得上面的fetch请求工具还需要哪些优化呢?欢迎在评论区留下的你的见解!
觉得有收获的朋友欢迎点赞,关注一波!
react 构建系列
企业级前端开发规范如何搭建 🛠
「React Build」之集成 Webpack5/React17
「React Build」之集成 CSS/Less/Sass/Antd
「React Build」之集成图片/字体
「React Build」之集成 Redux/Typescript
「React Build」之使用 Redux-thunk 实现 Redux 异步操作
「React Build」之集成 React-Router/Antd Menu 实现路由权限