更新记录

1.0.2(2025-04-16) 下载此版本

  • 修复拦截器为空数组导致请求中断问题。
  • 同步 RequestConfig 字段和官方的保持一致。

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

  • 初始版本发布。

1.0.0(2025-04-10) 下载此版本

  • 初始版本发布。
查看更多

平台兼容性

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

Kux-Flector 🚀

现代化请求库 | 全链路拦截器 | 智能Mock系统 | 企业级重试策略 License: MIT

特性亮点 ✨

  • 全链路拦截器 - 请求/响应/错误/mock全生命周期拦截
  • 智能Mock系统 - 正则匹配URL + 动态响应生成
  • 企业级重试 - 自适应重试策略 + 全链路拦截
  • 多环境支持 - 基于 uts 全平台兼容支持
  • UTS优先 - 完整的类型推导系统

快速开始 🚦

创建实例

import { createPipeline, PipelineInterceptors, Response, RequestEngine, RequestConfig } from '@/uni_modules/kux-flector';
import { request } from '@/uni_modules/kux-request-lite';

// 自定义接口响应类型
type Data = {
    id: number
    name: string
    age: number
}
type APIResponse = {
    route?: string
    method?: string
    statusCode: number
    message: string
    data?: Data[]
    error?: string
}
// 创建基础请求引擎
const uniEngine = async (config: RequestConfig<APIResponse>) => {
    const { data, error, response } = await request<APIResponse>({
        url: config.url,
        method: config.method,
        data: config.data,
        header: config.headers
    } as RequestOptions<APIResponse>);

    if (error != null) {
        throw error as Error;
    }

    return {
        statusCode: response!.statusCode,
        data: data!,
        headers: response.header == null ? {} as UTSJSONObject : (response!.header) as UTSJSONObject,
        cookies: response?.cookies
    } as Response<APIResponse>
};

// 构建请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    request: [], // 请求拦截器
    success: [], // 成功响应拦截器
    error: [], // 错误拦截器
    mock: [], // mock拦截器
} as PipelineInterceptors<APIResponse, any>);

注意

请求引擎支持自定义,类型符合 RequestEngine 即可。

核心功能 🔥

请求拦截

// 创建请求拦截器
const requestInterceptor = async (config: RequestConfig<APIResponse>) => {
    console.log('请求拦截', config);
    return config;
};

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    request: [requestInterceptor], // 请求拦截器
} as PipelineInterceptors<APIResponse, any>);

成功响应拦截

// 创建成功响应拦截器
const responseSuccessInterceptor = (async (response: Response<APIResponse>, config: RequestConfig<APIResponse>) => {
    console.log('响应拦截', response, config);
    if (response.statusCode > 200) {
        throw new Error(`请求失败,状态码:${response.statusCode}`);
    }
    // response.data.data = [{id: 1, name: '张三', age: 22} as Data];
    return response;
}) as SuccessInterceptor<APIResponse, APIResponse>;

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    success: [responseSuccessInterceptor], // 成功响应拦截器
} as PipelineInterceptors<APIResponse, any>);

错误拦截

// 创建错误拦截器
const errorInterceptor: ErrorInterceptor<any, APIResponse> = (async (error: any, config: RequestConfig<APIResponse>): Promise<any> => {
    console.log('错误拦截', error, config);
    // throw new Error('请求失败');
    return error;
});

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    error: [errorInterceptor], // 错误拦截器
} as PipelineInterceptors<APIResponse, any>);

自定义mock

// 构建mock规则
const mockRules = [{
    urlPattern: 'https://test.api.fdproxy.cn/user/list',
    method: 'GET',
    handler: (config): Response<APIResponse> => {
        return {
            statusCode: 200,
            data: {
                statusCode: 200,
                message: '请求成功',
                data: [{id: 1, name: 'User111', age: 22} as Data]
            } as APIResponse
        } as Response<APIResponse>;
    }
}, {
    urlPattern: /^\/api\/users\/(\d+)$/,
    method: 'GET',
    handler: (config): Response<APIResponse> => {
        return {
            statusCode: 200,
            data: {
                statusCode: 200,
                message: '请求成功',
                data: [{id: 1, name: 'User222', age: 22} as Data]
            } as APIResponse
        } as Response<APIResponse>;
    }
}, {
    urlPattern: /^\/api\/users\/retry\/(\d+)$/,
    method: 'GET',
    handler: (config): Response<APIResponse> => {
        return {
            statusCode: 500,
            data: {
                statusCode: 500,
                message: '请求失败'
            } as APIResponse
        } as Response<APIResponse>;
    }
}] as MockRule<APIResponse>[];

// 创建mock拦截器
const mockInterceptor = createMockInterceptor<APIResponse>(mockRules, null);

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    mock: [mockInterceptor], // mock拦截器
} as PipelineInterceptors<APIResponse, any>);

缓存拦截器

// 创建缓存拦截
const { request:cacheRequest, success:cacheSuccess } = createCacheInterceptor<APIResponse>({
    store: new MemoryCacheStore<APIResponse>() // 初始化缓存类实例
} as CreateCacheInterceptorOptions<APIResponse>);

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    request: [cacheRequest], // 请求注册,请求阶段获取缓存
    success: [cacheSuccess] // 响应注册,响应成功更新缓存
} as PipelineInterceptors<APIResponse, any>);

// 请求时开启缓存
apiClient({
    url: 'https://test.api.fdproxy.cn/user/list',
    method: 'GET',
    cacheKey: 'user/list', // 设置缓存key
    cacheTtl: 30_000, // 设置缓存时间30秒
    data: {
        id: 1
    }
})
.then((res: Response<APIResponse>) => {
    // 缓存返回的响应会附带 ____cacheHit: true
    console.log(res.cookies);
    console.log(res.headers);
    console.log(res.statusCode);
    console.log(res.data.data);
})
.catch((error) => {
    console.log(error);
})

注意

缓存类支持自定义,实现 CacheStore 接口即可。

请求重试拦截

请求重试是根据错误类型是否为 RetryableError 判断的,所以下面示例代码实例化请求错误方便拦截器链路根据错误类型决定是否需要发起请求重试。也可以自定义请求重试函数。只要符合 ErrorInterceptor 类型即可。插件默认提供了 createRetryInterceptor 函数开箱即用创建请求重试拦截。

// 在请求引擎中自定义重试错误
const uniEngine = async (config: RequestConfig<APIResponse>) => {
    const { data, error, response } = await request<APIResponse>({
        url: config.url,
        method: config.method,
        data: config.data,
        header: config.headers
    } as RequestOptions<APIResponse>);

    if (error != null) {
        throw error as Error;
    }

    // 根据响应内容状态码判断是否需要创建请求类型错误
    if (response != null && response.statusCode > 200) {
        if (response.statusCode == 501) {
            // 模拟创建重试请求错误
            const retryError = new RetryableError();
            retryError.code = 'RETRY_ERROR';
            retryError.response = {
                statusCode: response.statusCode,
                headers: response.header != null ? response.header as UTSJSONObject : null,
                data: response.data,
                cookies: response.cookies
            } as Response<APIResponse>;
            throw retryError;
        }

        throw new Error(`请求失败,状态码:${response.statusCode}`);
    }

    return {
        statusCode: response!.statusCode,
        data: data!,
        headers: response.header == null ? {} as UTSJSONObject : (response!.header) as UTSJSONObject,
        cookies: response?.cookies
    } as Response<APIResponse>
};

// 创建重试拦截
const { error: retryInterceptor } = createRetryInterceptor<APIResponse>({
    maxRetries: 3, // 最大重试次数
    retryDelay: 1000, // 重试间隔时间
    // 重试回调
    onRetry: (error, config, retryCount) => {
        console.log('开始重试:' + (retryCount + 1), error, config, retryCount);
    }
} as RetryStrategy<APIResponse>)

// 注入到请求管道
const apiClient = createPipeline<APIResponse, any>(uniEngine, {
    error: [retryInterceptor], // 在错误拦截中注册
} as PipelineInterceptors<APIResponse, any>);

API

createPipeline

  • 说明:创建请求管道客户端。

  • 类型

    function createPipeline<TResponse = any, TErrorResponse = any>(
        engine: RequestEngine<TResponse>, 
        interceptors?: PipelineInterceptors<TResponse, TErrorResponse>
    ): CreatePipelineCallback<TResponse> | null
  • 参数

    • engine: RequestEngine<TResponse>:请求引擎函数,可以自定义。
    • interceptors:PipelineInterceptors<TResponse, TErrorResponse> = {}:拦截器数组,包括请求、成功响应、错误、mock全链路拦截器类型
  • 返回值:返回附带全链路拦截器的请求客户端函数。

createMockInterceptor

  • 说明:创建mock拦截器函数。

  • 类型

    function createMockInterceptor<TResponse = any>(
        rules: MockRule<TResponse>[],
        fallback?: MockInterceptor<TResponse>
    ): MockInterceptor<TResponse>
  • 参数

    • rules: MockRule<TResponse>[]:自定义mock规则数组集。
    • fallback?: MockInterceptor<TResponse>:规则全部未匹配时回调函数。
  • 返回值:返回用于注入到请求管道 mock 拦截器的函数。

createCacheInterceptor

  • 说明:创建缓存拦截器函数。

  • 类型

    function createCacheInterceptor<T = any>(
        options: CreateCacheInterceptorOptions<T>
    ): CacheInterceptor<T>
  • 参数

    • options: CreateCacheInterceptorOptions<T>:创建缓存拦截器函数附带参数。
  • 返回值:返回用于注入到请求管道 requestsuccess 拦截器的两个函数。

createRetryInterceptor

  • 说明:创建请求重试拦截器函数。

  • 类型

    function createRetryInterceptor<TResponse = any>(
        defaultStrategy: RetryStrategy<TResponse, any> = {} as RetryStrategy<TResponse, any>
    ): CreateRetryInterceptorReturn<any, TResponse>
  • 参数

    • defaultStrategy: RetryStrategy<TResponse, any>:默认重试策略参数
  • 返回值:返回用于注入到请求管道 error 拦截器的函数。

Interface 实现

/**
 * interface.uts
 * uts插件接口定义文件,按规范定义接口文件可以在HBuilderX中更好的做到语法提示
 */

export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS';

/**
 * 重试策略定义
 */
export type RetryStrategy<TResponse = any, TError = any> = {
    /** 最大重试次数(默认 0) */
    maxRetries?: number;
    /** 重试间隔(默认 1000) */
    retryDelay?: number;
    /** 动态计算重试间隔的函数(优先级高于 retryDelay) */
    retryDelayCalculator?: (retryCount: number) => number;
    /** 触发重试的条件(返回 true 则重试) */
    shouldRetry?: (error: TError, config: RequestConfig<TResponse>) => boolean;
    /** 重试回调 */
    onRetry?: (error: TError, config: RequestConfig<TResponse>, retryCount: number) => void;
    /** 错误处理函数(返回自定义的错误响应) */
    transformFialError?: (error: TError, config: RequestConfig<TResponse>) => TError | Promise<TError>;
}

/**
 * 请求参数
 */
export type RequestConfig<TResponse = any> = {
    url: string;
    method?: HttpMethod;
    headers?: UTSJSONObject;
    data?: any;
    /** 缓存key */
    cacheKey?: string;
    /** 缓存时间 */
    cacheTtl?: number;
    /** 缓存策略 */
    cachePolicy?: 'force-cache' | 'no-cache';
    /** 重试策略 */
    retry?: RetryStrategy<TResponse, any>;
    /** 内部使用变量 */
    __retryCount?: number;
    /** 内部使用变量 */
    __cacheHit?: boolean;
    /** 内部使用变量 */
    __originalPipeline?: CreatePipelineCallback<TResponse>;
    /** 内部使用变量 */
    __cacheResponse?: Response<TResponse>;
}

/**
 * 自定义错误类型参数
 */
export type RetryErrorParams<TResponse = any> = {
    code: string;
    message: string;
    config: RequestConfig<TResponse>;
    response?: Response<TResponse>;
    retryCount: number;
}

/**
 * 成功响应
 */
export type Response<TResponse = any> = {
    statusCode: number;
    data: TResponse;
    headers?: UTSJSONObject;
    cookies?: string[];
}

/**
 * 请求引擎定义
 */
export type RequestEngine<TResponse = any> = (
    config: RequestConfig<TResponse>
) => Promise<Response<TResponse>>;

/**
 * 请求拦截器定义
 */
export type RequestInterceptor<TResponse = any> = (
    config: RequestConfig<TResponse>
) => RequestConfig | Promise<RequestConfig>;

/**
 * 成功响应拦截器定义
 */
export type SuccessInterceptor<TResponseIn = any, TResponseOut = any> = (
    response: Response<TResponseIn>,
    config: RequestConfig<TResponseOut>
) => Response<TResponseOut> | Promise<Response<TResponseOut>>;

/**
 * 错误拦截器定义
 */
export type ErrorInterceptor<TError = any, TResponse = any> = (
    error: TError,
    config: RequestConfig<TResponse>
) => Promise<TError>;

/**
 * 创建请求拦截器返回值
 */
export type CreateRetryInterceptorReturn<TError = any, TResponse = any> = {
    error: ErrorInterceptor<TError, TResponse>;
}

/**
 * mock规则
 */
export type MockRule<TResponse = any> = {
    /** 匹配url */
    urlPattern: RegExp | string;
    /** 匹配method */
    method?: HttpMethod | '*';
    /** 响应数据 */
    handler: (
        config: RequestConfig<TResponse>
    ) => Response<TResponse> | Promise<Response<TResponse>>;
}

/**
 * mock拦截器
 */
export type MockInterceptor<TResponse = any> = (
    config: RequestConfig<TResponse>
) => Response<TResponse> | Promise<Response<TResponse>> | null;

/**
 * 缓存拦截器定义
 */
export type CacheInterceptor<TResponse = any> = {
    request: RequestInterceptor<TResponse>; // 请求阶段检查缓存
    success: SuccessInterceptor<TResponse, TResponse>; // 成功阶段更新缓存
    // error: ErrorInterceptor<any>; // 失败阶段更新缓存
}

/**
 * 内存缓存存储值
 */
export type MemoryCacheStoreValue<TResponse = any> = {
    data: Response<TResponse>;
    expires?: number;
}

/**
 * 请求管道拦截器集合
 */
export type PipelineInterceptors<TResponse = any, TErrorResponse = any> = {
    mock?: Array<MockInterceptor<TResponse>>;
    request?: Array<RequestInterceptor<TResponse>>;
    success?: Array<SuccessInterceptor<TResponse, TResponse>>;
    error?: Array<ErrorInterceptor<TErrorResponse, TResponse>>;
    cache?: Array<CacheInterceptor<TResponse>>;
}

export type CreatePipelineCallback<TResponse> = (config: RequestConfig<TResponse>) => Promise<Response<TResponse>>;

/**
 * 缓存存储定义
 */
export interface CacheStore<T = any> {
    get(key: string): Promise<Response<T> | null>;
    set(key: string, value: Response<T>, ttl?: number): Promise<void>;
    delete(key: string): Promise<void>;
    clear(): Promise<void>;
}

/**
 * 创建缓存拦截器选项
 */
export type CreateCacheInterceptorOptions<T = any> = {
    /** 缓存存储 */
    store: CacheStore<T>;
    /** 缓存key生成器 */
    keyGenerator?: (config: RequestConfig<T>) => string;
}

// #ifdef APP-ANDROID
export declare function createPipeline<TResponse = any, TErrorResponse = any>(
    engine: RequestEngine<TResponse>,
    interceptors?: PipelineInterceptors<TResponse, TErrorResponse>
): CreatePipelineCallback<TResponse>;
// #endif

结语

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协议

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