基于 JavaScript fetch() API 的简单封装

JavaScript 的 fetch() API 提供了一种现代、易用的接口,用于从服务器异步获取资源。然而,在实际项目中,我们通常需要对基础的 fetch() 进行封装,以实现诸如添加默认配置、处理响应状态、自动解析响应数据、以及处理认证令牌等常见需求。

这个代码是一个比较基本的情况,你需要根据你自己项目的特点来对他进行一些适当的修改,比如,引入你所使用组件库的 Message 组件来显示提示或错误信息。或者根据后端的返回的数据结构来修改这里对数据的解析和对异常的处理。

讲解

定义参数类型

由于是 TypeScript 编写的,我们需要对它的 HttpMethod 和 ResponseType 参数进行类型的规制。
因此,我们要:

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
type ResponseType = "json" | "text" | "blob" | "arrayBuffer" | "formData";

获取 Token 令牌

我们把 getToken() 封装成一个函数,由于不同的项目获得 Token 的方式不一样,因此这里的 getToken() 函数要由用户自己实现。

/**
 * 获取当前用户的认证令牌。
 * @returns 返回当前用户的认证令牌,如果没有认证令牌则返回 null。
 */
const getToken = (): string | null => {
  // 获取 token 的代码根据需求来写。。。
};

封装的核心函数

http() 函数是整个封装的核心,它定义了函数的参数类型,以及如何处理响应状态、处理认证令牌等。

export async function http(
  method: HttpMethod,
  url: string,
  data?: any,
  responseType: ResponseType = "json",
  headers?: HeadersInit,
  noToken: boolean = false
): Promise<any> {
  // 内容。。。
}
定义 BASE_URL 和 Token

这里的 BASE_URL 是写死的,因为是个 demo 的原因,你可以自己写在配置文件并引入进来。

const BASE_URL = "/api";
const AUTH_TOKEN = noToken ? null : getToken();
添加默认配置
/**
 * 配置网络请求的初始化参数
 * @param method 请求方法(如GET、POST等)
 * @param headers 请求头信息,可以是预设的或用户自定义的
 * @param data 请求体数据,如果有的话
 * @param AUTH_TOKEN 认证令牌,如果存在则会添加到请求头中
 * @returns 返回一个配置好的 RequestInit 对象,可用于fetch等网络请求中
 */
const config: RequestInit = {
  method,
  headers: new Headers({
    "Content-Type": "application/json; charset=utf-8",
    ...headers,
    ...(AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {}),
  }),
  ...(data ? { body: data } : {}),
};
序列化数据。

为了保证发送数据时候的准确性,当 data 类型是对象的时候,我们会序列号一下确保正确。

// 如果请求方法需要数据并且数据是对象类型,则序列化数据。
if (["POST", "PUT", "PATCH"].includes(method) && typeof data === "object") {
  config.body = JSON.stringify(data);
}
开始请求
try {

try 语句开始一个异常处理块,用于捕获在该块内部可能抛出的任何错误。

const response = await fetch(BASE_URL + url, config);

使用 await 关键字等待 fetch 函数的异步执行结果。fetch 函数发起一个到指定 URL(由 BASE_URLurl 拼接而成)的 HTTP 请求,并接受一个配置对象 config 作为参数,用于设置请求头、方法等信息。请求完成后,返回一个 Response 对象赋值给常量 response

if (!response.ok) {
  throw new Error(`HTTP error! status: ${response.status}`);
}

检查 response对象的 ok 属性(fetch() API 自带的)。若其值为 false(表示 HTTP 状态码不在 2xx 范围内,即请求未成功),则抛出一个新的 Error 对象,其中包含关于 HTTP 错误的自定义消息,包括具体的错误状态码。

switch (responseType) {
  case "json":
    return response.json();
  case "text":
    return response.text();
  case "blob":
    return response.blob();
  case "arrayBuffer":
    return response.arrayBuffer();
  case "formData":
    return response.formData();
  default:
    throw new Error("Unsupported response type");
}

使用 switch 语句根据传入的 responseType 变量进行分支判断。根据不同的值,调用 response 对象对应的解析方法来处理响应数据,并返回解析结果:

  • json: 解析为 JSON 对象。
  • text: 解析为纯文本字符串。
  • blob: 解析为 Blob 对象(二进制大对象)。
  • arrayBuffer: 解析为 ArrayBuffer 对象(用于表示通用的、固定长度的原始二进制数据缓冲区)。
  • formData: 解析为 FormData 对象(用于存储键值对,通常用于发送表单数据)。

responseType值不属于上述任何情况,则默认分支抛出一个错误,提示不支持的响应类型。

} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}

catch 语句中捕获在 try 块中抛出的所有错误。首先,使用 console.error 将包含详细错误信息的消息输出到控制台。接着,重新抛出(throw error)同一错误,以便调用者能够继续处理或捕获此错误。

}

结束整个 try…catch 异常处理块。

完整代码

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
type ResponseType = "json" | "text" | "blob" | "arrayBuffer" | "formData";

/**
 * 获取当前用户的认证令牌。
 * @returns 返回当前用户的认证令牌,如果没有认证令牌则返回 null。
 */
const getToken = (): string | null => {
  // 获取 token 的代码根据需求来写。。。
};

/**
 * 执行HTTP请求的通用函数。
 * @param method 请求方法,支持GET、POST、PUT、DELETE和PATCH。
 * @param url 请求的URL。
 * @param data 可选,请求的数据。
 * @param responseType 可选,响应的数据类型,默认为"json"。支持的类型有"json"、"text"、"blob"、"arrayBuffer"和"formData"。
 * @param headers 可选,请求头信息。
 * @param noToken 可选,就算本地存储了 Token 也不携带,默认为 false。
 * @returns 返回一个Promise,解析为请求结果。
 */
export async function http(
  method: HttpMethod,
  url: string,
  data?: any,
  responseType: ResponseType = "json",
  headers?: HeadersInit,
  noToken: boolean = false
): Promise<any> {
  const BASE_URL = "/api";
  const AUTH_TOKEN = noToken ? null : getToken();

  /**
   * 配置网络请求的初始化参数
   * @param method 请求方法(如GET、POST等)
   * @param headers 请求头信息,可以是预设的或用户自定义的
   * @param data 请求体数据,如果有的话
   * @param AUTH_TOKEN 认证令牌,如果存在则会添加到请求头中
   * @returns 返回一个配置好的 RequestInit 对象,可用于fetch等网络请求中
   */
  const config: RequestInit = {
    method,
    headers: new Headers({
      "Content-Type": "application/json; charset=utf-8",
      ...headers,
      ...(AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {}),
    }),
    ...(data ? { body: data } : {}),
  };

  // 如果请求方法需要数据并且数据是对象类型,则序列化数据。
  if (["POST", "PUT", "PATCH"].includes(method) && typeof data === "object") {
    config.body = JSON.stringify(data);
  }

  try {
    const response = await fetch(BASE_URL + url, config);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    // 根据响应类型处理响应数据
    switch (responseType) {
      case "json":
        return response.json();
      case "text":
        return response.text();
      case "blob":
        return response.blob();
      case "arrayBuffer":
        return response.arrayBuffer();
      case "formData":
        return response.formData();
      default:
        throw new Error("Unsupported response type");
    }
  } catch (error) {
    console.error("There was a problem with the fetch operation:", error);
    throw error;
  }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

narukeu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值