更新记录

1.0.1(2025-01-10) 下载此版本

  • 修复控制台提示 promise 异常问题。
  • 新增 handleResponseErrorWithRetry 处理响应错误并重试方法。调用示例代码:

    • 请求库调用演示
    // 假设 `response` 是响应错误的结果
    if (response != null) {
        // 请求库实例设置的当前重试次数标识
        this.attempts++;
        /**
         * this.retryRequest为请求库实例设置的存储当前重试请求
         */
        // #ifndef APP-ANDROID
        this.retryRequest = (url, options) => this.request(url, options);
        // #endif
        // #ifdef APP-ANDROID
        this.retryRequest = UTSAndroid.getKotlinFunction(request) as RetryFunction<RequestConfig, RequestSuccess<Response>> | null;
        // #endif
        if (this.interceptorManager.get(this.interceptorId)?.responseInterceptorErrorWithRetry == null) {
            return await this.interceptorManager.handleResponseError(response);
        }
        if (this.attempts <= retryTimes && this.retryRequest != null) {
            const withRetryOptions = {
                response,
                retryOptions: {
                    retryTimes: this.attempts,
                    retry: this.retryRequest as RetryFunction<RequestConfig, RequestSuccess<Response>>
                } as RetryOptions<RequestConfig, RequestSuccess<Response>>
            } as ResponseErrorCallbackOptions<RequestConfig, RequestSuccess<Response>>
            return (await this.interceptorManager.handleResponseErrorWithRetry(withRetryOptions));
        }
    }
    • 页面使用演示
    // 假设httpService是初始化过的请求库实例
    httpService.use({
        ...其他拦截器方法
        // 请求重试拦截
        responseInterceptorErrorWithRetry: async (options): Promise<RequestSuccess<Response> | null> => {
            console.log('请求失败了可以重新尝试', options);
            return options.retryOptions.retry('https://test.api.fdproxy.cn/user/list', {} as RequestConfig);
        }
    } as RIInterceptor<RequestConfig, RequestSuccess<Response>>);

    提示

    请求重试拦截实例可以看文档最下面 完整自定义请求拦截示例

1.0.0(2025-01-06) 下载此版本

  • 初始版本发布。

平台兼容性

Vue2 Vue3
×
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.6.8,Android:支持,iOS:支持,HarmonyNext:不支持 × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序 鸿蒙元服务
× × × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari

kux-request-interceptors

该插件是和请求库解耦的拦截器插件,可以适用于任何请求拦截封装场景,旨在为开发者们大量简化请求拦截的实现代码。

插件特色

  • 适应任何请求库封装
  • 简洁的API设计
  • 支持泛型
  • 和请求库完全解耦

基本用法

1.创建自定义的请求类,通过 use 方法注册拦截器,示例如下:

import { RIInterceptorManager, RIInterceptorManagerImpl, RIInterceptor } from '@/uni_modules/kux-request-interceptors';

export class HttpService {
    private interceptorManager : RIInterceptorManager<RequestConfig, RequestSuccess<Response>>;

    constructor() {
        // 初始化拦截器
        this.interceptorManager = new RIInterceptorManagerImpl<RequestConfig, RequestSuccess<Response>>();
    }

    /**
     * 实现拦截器注册,方法名可以自定义,通过拦截器插件的 `use` 方法注册
     */
    use(interceptor : RIInterceptor<RequestConfig, RequestSuccess<Response>>) : string {
        return this.interceptorManager.use(interceptor);
    }

    /**
     * 自定义请求
     */
    async request(url: string, config: RequestConfig = {}): Promise<Response | null> {
        // 这里通过插件的 `handleRequest` 方法注册请求拦截,拿到拦截处理后的请求参数
        const beforeConfig = await this.interceptorManager.handleRequest(options);
        // 这里写自己的请求逻辑代码,比如二次处理合并请求参数等等,此处省略
        // 这里通过拦截器插件的 `handleRequestError` 方法注册请求错误拦截
        if (error != null) {
            const err = await this.interceptorManager.handleRequestError(error);
            if (err != null) {
                return Promise.reject(err) as Promise<IUniError>;
            }
        }
        // 这里通过插件的 `handleResponse` 方法注册响应拦截
        if (response != null && response.data != null) {
            if (response.statusCode >= 200 && response.statusCode <= 299) {
                return (await this.interceptorManager.handleResponse(response))!.data;
            }
            // 这里通过插件的 `handleResponseError` 方法注册响应错误
            return (await this.interceptorManager.handleResponseError(response))!.data;
        }
        return Promise.resolve(null as any | null);
    } 
}

2.页面中使用自定义请求类

import { HttpService, RequestConfig, Data, Response } from '../../service/HttpService';

const httpService = new HttpService();

// 注册拦截器
httpService.use({
    requestInterceptor: async (config: RequestConfig): Promise<RequestConfig> => {
        console.log('进入请求拦截器', config);
        config.data = {
            a: 1
        }
        return config;
    },
    responseInterceptor: async (response): Promise<RequestSuccess<Response>> => {
        console.log('进入响应拦截器', response);
        if (response.data?.message != null) {
            response.data!.message = '请求成功测试';
        }
        return response;
    },
    requestInterceptorError: async (error: IUniError): Promise<IUniError | null> => {
        console.log('网络错误了', error);
        return error;
    },
    responseInterceptorError: async (response): Promise<RequestSuccess<Response> | null> => {
        console.log('请求失败了', response);
        // Promise.reject('请求失败了哈哈哈');
        return response;
    },
    responseInterceptorErrorWithRetry: async (options): Promise<RequestSuccess<Response> | null> => {
        console.log('请求失败了可以重新尝试', options);
        return options.retryOptions.retry('https://test.api.fdproxy.cn/user/list', {} as RequestConfig);
    }
} as RIInterceptor<RequestConfig, RequestSuccess<Response>>);

// 发起请求测试
httpService.request('https://test.api.cn/user/list')
        .then((response) => {
            console.log(response);
            if (response != null) {
                // const res = response as Response;
                const data = response.data;
                if (data != null) {
                    console.log(data[0].name);
                }
            }
        })
        .catch((error) => {
            console.log(error);
        })

提示

上面的 RequestConfig 为自定义的请求参数类型定义,Response 为自定义的响应结果参数类型

实现请求类时上下文类型一定要保持一致,比如实例化拦截器时 new RIInterceptorManagerImpl<T, R>T 对应请求参数类型,R 对应响应结果类型。

请求重试拦截实例可以看文档最下面 完整自定义请求拦截示例

API

RIInterceptorManagerImpl

  • 说明:拦截管理器实现类
  • 类型:class RIInterceptorManagerImpl<T, R>

RIInterceptorManagerImpl 方法说明

use

  • 说明:注册拦截器
  • 类型:use (interceptor: RIInterceptor<T, R>): string
  • 返回值:返回当前拦截器id

eject

  • 说明:移除指定的拦截器
  • 类型:eject(id: string): void

clear

  • 说明:清除所有的拦截器
  • 类型:clear(): void

get

  • 说明:获取指定的拦截器
  • 类型:get(id: string): RIInterceptor<T, R> | null
  • 返回值:返回拦截器实例,如果不存在返回null

handleRequest

  • 说明:处理请求拦截
  • 类型:handleRequest(config: T): Promise<T>

handleResponse

  • 说明:处理响应拦截
  • 类型:handleResponse(response: R): Promise<R>

handleRequestError

  • 说明:处理请求错误拦截,一般是比如网络错误,请求地址错误等等场景
  • 类型:handleRequestError(error: IUniError): Promise<IUniError | null>

handleResponseError

  • 说明:处理响应错误拦截,一般是比如接口参数错误,接口返回自定义错误等场景
  • 类型:handleResponseError(response: R): Promise<R | null>

handleResponseErrorWithRetry

  • 说明:处理响应错误并重试,一般是比如自动续签token等类似场景使用。
  • 类型:handleResponseErrorWithRetry(options: ResponseErrorCallbackOptions<T, R>): Promise<R | null>;

ResponseErrorCallbackOptions 参数说明

  • 说明:响应错误并重试函数参数
  • 泛型参数:ResponseErrorCallbackOptions<T, R>

    • T 请求参数类型
    • R 响应结果类型

    response

    • 说明:重试回调的原始响应内容
    • 类型:R

    retryOptions

    • 说明:重试参数,包含 retryTimes 重试次数和 retry 重试函数
    • 类型:RetryOptions<T, R>

RetryOptions 参数说明

  • 说明:重试参数内容
  • 泛型参数:RetryOptions<T, R>

    • T 请求参数类型
    • R 响应结果类型

    retryTimes

    • 说明:重试次数,重试次数会依此递减直至为0不再重试
    • 类型:number

    retry

    • 说明:发起重试的函数,也就是当前请求函数实例
    • 类型:RetryFunction<T, R>

RetryFunction 参数说明

  • 说明:发起重试的函数类型
  • 类型:type RetryFunction<T, R> = (url: string, config: T) => Promise<R | null>
    • T 请求参数类型
    • R 响应结果类型

完整自定义请求拦截示例

import { request as _request } from '@/uni_modules/kux-request-lite';
import { RIInterceptorManager, RIInterceptorManagerImpl, RIInterceptor, ResponseErrorCallbackOptions, RetryOptions, RetryFunction } from '@/uni_modules/kux-request-interceptors';

/**
 * 自定义请求配置
 */
export type RequestConfig = {
    data ?: any;
    header ?: UTSJSONObject;
    method ?: string;
    timeout ?: number;
    withCredentials ?: boolean;
    firstIpv4 ?: boolean;
}

export type Data = {
    id : number
    name : string
    age : number
}

export type Response = {
    route ?: string
    method ?: string
    statusCode : number
    message : string
    data ?: Data[]
    error ?: string
}

/**
 * 使用拦截器请求服务演示类
 */
export class HttpService {
    private interceptorManager : RIInterceptorManager<RequestConfig, RequestSuccess<Response>>;
    // 记录已经重试的次数
    private attempts : number = 0;
    // 存储需要重试的函数
    private retryRequest: RetryFunction<RequestConfig, RequestSuccess<Response>> | null;
    // 记录当前拦截器唯一标识,后面用来获取当前拦截器使用
    private interceptorId: string = '';

    constructor() {
        this.interceptorManager = new RIInterceptorManagerImpl<RequestConfig, RequestSuccess<Response>>();
        this.retryRequest = null;
    }
    /**
     * 实现拦截器注册
     */
    use(interceptor : RIInterceptor<RequestConfig, RequestSuccess<Response>>) : string {
        this.interceptorId = this.interceptorManager.use(interceptor);
        return this.interceptorId;
    }

    async request(url : string, options : RequestConfig = {} as RequestConfig) : Promise<Response | null> {
        const { retryTimes = 3 } = options;
        const beforeConfig = await this.interceptorManager.handleRequest(options);
        const { response, error } = await _request<Response>({
            url: url,
            data: beforeConfig.data,
            header: beforeConfig.header,
            method: beforeConfig.method,
            timeout: beforeConfig.timeout,
            withCredentials: beforeConfig.withCredentials,
            firstIpv4: beforeConfig.firstIpv4,
        } as RequestOptions<Response>);
        if (error != null) {
            const err = await this.interceptorManager.handleRequestError(error);
            if (err != null) {
                return Promise.reject(err) as Promise<IUniError>;
            }
        }
        if (response != null && response.data != null) {
            if (response.statusCode >= 200 && response.statusCode <= 299) {
                return (await this.interceptorManager.handleResponse(response))!.data;
            }

            this.attempts++;
            // #ifndef APP-ANDROID
            this.retryRequest = (url, options) => this.request(url, options);
            // #endif
            // #ifdef APP-ANDROID
            this.retryRequest = UTSAndroid.getKotlinFunction(request) as RetryFunction<RequestConfig, RequestSuccess<Response>> | null;
            // #endif
            if (this.interceptorManager.get(this.interceptorId)?.responseInterceptorErrorWithRetry == null) {
                return await this.interceptorManager.handleResponseError(response);
            }
            if (this.attempts <= retryTimes && this.retryRequest != null) {
                const withRetryOptions = {
                    response,
                    retryOptions: {
                        retryTimes: this.attempts,
                        retry: this.retryRequest as RetryFunction<RequestConfig, RequestSuccess<Response>>
                    } as RetryOptions<RequestConfig, RequestSuccess<Response>>
                } as ResponseErrorCallbackOptions<RequestConfig, RequestSuccess<Response>>
                return (await this.interceptorManager.handleResponseErrorWithRetry(withRetryOptions));
            }
        }
        return Promise.resolve(null as any | null);
    }
}

结语

kux 不生产代码,只做代码的搬运工,致力于提供uts 的 js 生态轮子实现,欢迎各位大佬在插件市场搜索使用 kux 生态插件:https://ext.dcloud.net.cn/search?q=kux

友情推荐

  • TMUI4.0:包含了核心的uts插件基类.和uvue组件库
  • GVIM即时通讯模版:GVIM即时通讯模版,基于uni-app x开发的一款即时通讯模版
  • t-uvue-ui:T-UVUE-UI是基于UNI-APP X开发的前端UI框架
  • UxFrame 低代码高性能UI框架:【F2图表、双滑块slider、炫酷效果tabbar、拖拽排序、日历拖拽选择、签名...】UniAppX 高质量UI库
  • wx-ui 基于uni-app x开发的高性能混合UI库:基于uni-app x开发的高性能混合UI库,集成 uts api 和 uts component,提供了一套完整、高效且易于使用的UI组件和API,让您以更少的时间成本,轻松完成高性能应用开发。
  • firstui-uvue:FirstUI(unix)组件库,一款适配 uni-app x 的轻量、简洁、高效、全面的移动端组件库。
  • easyXUI 不仅仅是UI 更是为UniApp X设计的电商模板库:easyX 不仅仅是UI库,更是一个轻量、可定制的UniAPP X电商业务模板库,可作为官方组件库的补充,始终坚持简单好用、易上手

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问