前端程序员:我写了一个超牛的API工具,老板直呼“内行”!

Python私教 2025-01-12 10:41:16
开场白:

大家好,我是你们的老朋友,一个每天都在和 Bug 斗智斗勇的前端程序员。今天我要给大家分享一个我最近写的“神器”——一个超级强大的 API 客户端工具。它不仅让我的工作效率翻倍,还让我的老板直呼“内行”!如果你也在为网络请求的复杂性头疼,那这篇文章你一定要看完!

正文:1. 为什么我要写这个工具?

作为一个前端程序员,我每天都要和 API 打交道。GET、POST、PUT、DELETE……这些 HTTP 方法就像我的“老朋友”,但有时候它们也会让我抓狂。比如:

请求超时了怎么办?网络波动导致请求失败了怎么办?用户突然离开页面,未完成的请求怎么取消?重复请求同一个接口,能不能缓存一下?

于是,我决定自己动手,写一个“万能”的 API 工具,解决这些问题!经过一番折腾,终于搞定了,效果还不错,老板看了直呼“内行”!

2. 这个工具到底有多牛?

先来看看它的核心功能:

请求超时控制:再也不用担心请求卡死了,超时自动取消!请求重试机制:网络波动?不怕!自动重试,最多 3 次!请求取消功能:用户突然离开页面?一键取消未完成的请求!请求缓存:重复请求同一个接口?直接返回缓存结果,性能提升 100%!并发控制:同时发起太多请求?自动排队,避免资源耗尽!灵活的拦截器:想在请求前后加点“私货”?拦截器帮你搞定!

是不是听起来就很厉害?别急,代码在后面,咱们慢慢看!

3. 代码展示:一看就懂,一学就会!

以下是这个工具的完整代码(基于 JavaScript):

class Api{    constructor(baseUrl, headers = {}, maxConcurrentRequests = 5) {        this.baseUrl = baseUrl;        this.headers = {            'Content-Type': 'application/json',            ...headers,        };        this.requestInterceptors = [];        this.responseInterceptors = [];        this.maxConcurrentRequests = maxConcurrentRequests;        this.currentRequests = 0;        this.requestQueue = [];        this.cache = new Map();        this.abortControllers = new Map();    }    async request(endpoint, method, body = null, credentials = 'omit', timeout = 10000, retries = 3, useCache = false, customConfig = {}) {        const cacheKey = `${method}:${endpoint}`;        // 使用缓存        if (useCache && this.cache.has(cacheKey)) {            return this.cache.get(cacheKey);        }        // 并发控制        if (this.currentRequests >= this.maxConcurrentRequests) {            await new Promise((resolve) => this.requestQueue.push(resolve));        }        this.currentRequests++;        let lastError;        for (let i = 0; i < retries; i++) {            try {                const result = await this._request(endpoint, method, body, credentials, timeout, customConfig);                if (useCache) {                    this.cache.set(cacheKey, result);                }                return result;            } catch (error) {                lastError = error;                if (i === retries - 1) {                    throw lastError;                }            }        }    }    async _request(endpoint, method, body, credentials, timeout, customConfig) {        const controller = new AbortController();        const timeoutId = setTimeout(() => controller.abort(), timeout);        // 存储 controller 以便后续取消        this.abortControllers.set(endpoint, controller);        let config = {            method,            headers: this.headers,            credentials,            signal: controller.signal,            ...customConfig,        };        if (body) {            config.body = JSON.stringify(body);        }        // 执行请求拦截器        for (let interceptor of this.requestInterceptors) {            config = await interceptor(config, endpoint, method);        }        const url = `${this.baseUrl}${endpoint}`;        let response;        try {            response = await fetch(url, config);            if (!response.ok) {                throw new ApiError(`HTTP 错误! 状态码: ${response.status}`, response.status, response, config);            }        } catch (error) {            console.error('请求失败:', error);            throw error;        } finally {            clearTimeout(timeoutId);            this.abortControllers.delete(endpoint);            this.currentRequests--;            if (this.requestQueue.length > 0) {                this.requestQueue.shift()();            }        }        // 执行响应拦截器        for (let interceptor of this.responseInterceptors) {            response = await interceptor(response, endpoint, method);        }        return await response.json();    }    async get(endpoint, queryParams = {}, credentials = 'omit', timeout = 10000, retries = 3, useCache = false) {        let fullEndpoint = endpoint;        if (Object.keys(queryParams).length > 0) {            const queryString = new URLSearchParams(queryParams).toString();            fullEndpoint += `?${queryString}`;        }        return this.request(fullEndpoint, 'GET', null, credentials, timeout, retries, useCache);    }    async post(endpoint, body, credentials = 'omit', timeout = 10000, retries = 3) {        return this.request(endpoint, 'POST', body, credentials, timeout, retries);    }    async put(endpoint, body, credentials = 'omit', timeout = 10000, retries = 3) {        return this.request(endpoint, 'PUT', body, credentials, timeout, retries);    }    async patch(endpoint, body, credentials = 'omit', timeout = 10000, retries = 3) {        return this.request(endpoint, 'PATCH', body, credentials, timeout, retries);    }    async delete(endpoint, credentials = 'omit', timeout = 10000, retries = 3) {        return this.request(endpoint, 'DELETE', null, credentials, timeout, retries);    }    useRequestInterceptor(interceptor) {        this.requestInterceptors.push(interceptor);    }    useResponseInterceptor(interceptor) {        this.responseInterceptors.push(interceptor);    }    cancelRequest(endpoint) {        if (this.abortControllers.has(endpoint)) {            this.abortControllers.get(endpoint).abort();            this.abortControllers.delete(endpoint);        }    }    clearCache() {        this.cache.clear();    }}class ApiError extends Error{    constructor(message, statusCode, response, config) {        super(message);        this.statusCode = statusCode;        this.response = response;        this.config = config;    }}export default Api;

4. 使用示例:简单到哭!

const api = new Api('https://api.example.com', { Authorization: 'Bearer token' });// 添加请求拦截器api.useRequestInterceptor(async (config, endpoint, method) => {    console.log(`请求拦截器: ${method} ${endpoint}`);    return config;});// 发起 GET 请求(带缓存)api.get('/users', { page: 1 }, 'include', 10000, 3, true)    .then(data => console.log(data))    .catch(error => console.error(error));// 发起 POST 请求api.post('/users', { name: 'John' })    .then(data => console.log(data))    .catch(error => console.error(error));

5. 总结:这个工具为什么值得你拥有?高效:解决网络请求中的各种痛点,提升开发效率。灵活:支持自定义配置、拦截器、缓存等功能。稳定:超时、重试、取消等机制,确保请求的稳定性。

如果你觉得这个工具不错,欢迎点赞、转发、打赏!你的支持是我持续分享的动力!

结尾:

好了,今天的分享就到这里。如果你觉得这篇文章对你有帮助,别忘了关注我,我会持续分享更多实用的技术干货!如果你有任何问题或建议,欢迎在评论区留言,我会一一回复!

求关注、求转发、求打赏!你们的支持是我最大的动力!

互动话题:

你在开发中遇到过哪些网络请求的坑?欢迎在评论区分享你的故事!

0 阅读:4

Python私教

简介:全栈工程师,目标人工智能.抖音同理想国真恵玩.