SHIMMER
fetch二次封装
前端|其它
发布于2023-09-25 最近修改2023-12-22
1267
0
Shimmer

fetch二次封装

每次新建项目都需要对请求进行封装,但是每个项目封装的方式都不一样,而且之前都是基于axios的二次封装,以下是我对fetch的二次封装,用作新建项目的基建api。
javascript
复制代码
type FetchType = { url: string; method: keyof typeof HttpMethod; // HTTP请求方法类型 data?: any; // 请求数据 contentType?: keyof typeof ContentType; // 请求内容类型 headers?: HeadersInit; // 请求头 config?: RequestInit; // fetch配置项 timeout?: number; // 请求超时时间 }; const initConfig: any = { env: process.env.NODE_ENV || "development", // 环境变量 baseUrlObj: { development: "", // 开发环境的基础URL production: "", // 生产环境的基础URL }, contentType: "JSON", // 默认的请求内容类型 timeout: 5000, // 默认的请求超时时间 }; // 定义ContentType的enum export const ContentType = { JSON: "application/json", FORM: "application/x-www-form-urlencoded", TEXT: "text/plain", BLOB: "application/octet-stream", ARRAYBUFFER: "application/octet-stream", }; // 定义method的enum const HttpMethod = { GET: "GET", POST: "POST", PUT: "PUT", DELETE: "DELETE", }; function fetchRequest({ url, method, data, contentType = initConfig.contentType, headers, config, timeout = initConfig.timeout, }: FetchType) { let options: { [key: string]: any } = { method, headers: { "Content-Type": ContentType[contentType], // 设置请求头的Content-Type ...headers, }, mode: "cors", // 其他fetch配置项 ...config, }; if (!/^http(s?):\/\//i.test(url)) { url = (initConfig.baseUrlObj[initConfig.env] || "") + url; // 拼接完整的请求URL } if (method !== "GET" && data) { options.body = contentType === "JSON" ? JSON.stringify(data) : new URLSearchParams(data); // 根据请求内容类型设置请求体数据 } // 发送请求前调用请求拦截器 if (fetchRequest.requestInterceptor) { options = fetchRequest.requestInterceptor(options); } let cancel; // 取消请求配置 const cancelToken = new Promise((resolve) => { cancel = () => resolve({ code: "END", msg: "Request termination" }); }); // 超时配置 const timeoutPromise = new Promise((_resolve, reject) => { setTimeout(() => { reject({ code: "ERROR", msg: "请求超时", }); }, timeout); }); // 真实请求配置 const requestPromise = new Promise((resolve, reject) => { fetch(url, options) .then((response) => { let newResponse; // 处理响应前调用响应拦截器 if (fetchRequest.responseInterceptor) { newResponse = fetchRequest.responseInterceptor(response, contentType); } resolve(newResponse); }) .catch((error) => { // 处理错误前调用错误处理函数 if (fetchRequest.errorHandler) { fetchRequest.errorHandler(error); } reject(error); }); }); // 返回一个包含请求和取消函数的对象 return { request: Promise.race([cancelToken, timeoutPromise, requestPromise]), cancel, }; } // 自定义请求拦截器 fetchRequest.requestInterceptor = async (options: any) => { const { method, data, contentType } = options; // 在这里可以对请求config进行处理,比如添加token等 if (method !== "GET" && data && contentType === "FORM") { // 序列化表单数据 const formData: any = new URLSearchParams(); Object.entries(data).forEach(([key, value]) => { formData.append(key, value); }); // 更新请求体和请求头的配置 options.body = formData; } return options; }; // 自定义响应拦截器 fetchRequest.responseInterceptor = async ( response: any, contentType: keyof typeof ContentType ) => { // 在这里可以对响应response进行处理,比如处理错误码等 let { status, statusText } = response; if (status >= 200 && status < 400) { let result; switch (contentType) { case "JSON": result = response.json(); break; case "TEXT": result = response.text(); break; case "BLOB": result = response.blob(); break; case "ARRAYBUFFER": result = response.arrayBuffer(); break; case "FORM": // 添加对 FORM 类型的处理 result = response.formData(); break; default: result = response; } return result; } return { code: "STATUS ERROR", status, statusText, }; }; // 自定义错误处理函数 fetchRequest.errorHandler = function (error: any) { // 在这里可以对错误进行处理,比如弹窗提示等 console.log("请求发生错误:", error); }; /* ———— 以下对不同请求又加了一层封装 —————————————————————————————————————————————————————————————— */ type Options = { isCancel?: boolean; config?: RequestInit; headers?: HeadersInit; contentType?: keyof typeof ContentType; data?: any; }; type GetFunction = (url: string, options?: Options) => Promise<any>; type PostFunction = (url: string, options?: Options) => Promise<any>; type PutFunction = (url: string, options?: Options) => Promise<any>; type DeleteFunction = (url: string, options?: Options) => Promise<any>; export const get: GetFunction = async (url: string, options: Options = {}) => { if (options.isCancel) { return fetchRequest({ url, method: "GET", ...options }); // 根据选项是否取消请求来调用fetchRequest } const fetchObj = fetchRequest({ url, method: "GET" }); return new Promise((resolve, reject) => { fetchObj.request.then(resolve).catch(reject); }); }; export const post: PostFunction = async ( url: string, options: Options = {} ) => { if (options.isCancel) { return fetchRequest({ url, method: "POST", ...options }); } const fetchObj = fetchRequest({ url, method: "POST", ...options }); return new Promise((resolve, reject) => { fetchObj.request.then(resolve).catch(reject); }); }; export const put: PutFunction = async (url: string, options: Options = {}) => { if (options.isCancel) { return fetchRequest({ url, method: "PUT", ...options }); } const fetchObj = fetchRequest({ url, method: "PUT", ...options }); return new Promise((resolve, reject) => { fetchObj.request.then(resolve).catch(reject); }); }; export const del: DeleteFunction = async ( url: string, options: Options = {} ) => { if (options.isCancel) { return fetchRequest({ url, method: "DELETE", ...options }); } const fetchObj = fetchRequest({ url, method: "DELETE", ...options }); return new Promise((resolve, reject) => { fetchObj.request.then(resolve).catch(reject); }); };

结尾

目录