阅读 205

「超详细React项目搭建教程七」封装 Fetch 请求

fetch API是原生 JavaScript 提供的一个概念,主要用来与 Web 服务器进行交互。 我们如何在asyncawait中使用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 服务进行交互变得非常容易。

参考文档:

最后

当然!还有许多请求过程中的问题需要判断和处!咱们后续再更新,敬请期待!

你觉得上面的fetch请求工具还需要哪些优化呢?欢迎在评论区留下的你的见解!

觉得有收获的朋友欢迎点赞关注一波!

往期文章

react 构建系列

  1. 企业级前端开发规范如何搭建 🛠
  2. 「React Build」之集成 Webpack5/React17
  3. 「React Build」之集成 CSS/Less/Sass/Antd
  4. 「React Build」之集成图片/字体
  5. 「React Build」之集成 Redux/Typescript
  6. 「React Build」之使用 Redux-thunk 实现 Redux 异步操作
  7. 「React Build」之集成 React-Router/Antd Menu 实现路由权限
文章分类
前端
文章标签