npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bugfix2019/request-middleware

v0.0.2

Published

A powerful request middleware library with context support. Supports axios, xhr, and fetch.

Readme

@bugfix2019/request-middleware

npm version License

强大的请求中间件库,支持 ctx 上下文,兼容 axios、xhr 和 fetch。

📖 前言

这个库的设计灵感来源于多个优秀的框架和库:

  • Express:中间件是 (req, res, next),通过 next() 控制后续中间件执行。expressjs.com
  • Koa:中间件是 (ctx, next),通过 await next() 实现经典「洋葱模型」:next() 前是请求前逻辑,next() 后是请求后逻辑。github.com/koajs/koa
  • Gin:中间件函数 func(c *gin.Context) 内部调用 c.Next()Next() 前可以做前置处理,Next() 后可以做后置处理和耗时统计。gin-gonic.com

受这些启发的驱动,我们希望在前端请求层面实现类似的中间件机制。通过解耦业务逻辑和通用处理(如日志、错误处理、重试等),只需一个人维护中间件,业务同学可以专注于核心业务逻辑,大大提升开发效率和代码可维护性。

✨ 特性

  • 🎯 100% TypeScript - 完整的类型支持
  • 🧅 洋葱模型 - Koa 风格的中间件机制
  • 🔗 上下文支持 - 贯穿请求生命周期的 ctx 对象
  • 🔌 适配器模式 - 支持 axios,可扩展至 xhr/fetch
  • 📦 官方中间件 - 内置日志、重试、缓存等中间件
  • 🔄 EventSource 支持 - 支持 Server-Sent Events (SSE) via @microsoft/fetch-event-source
  • 🚀 零核心依赖 - 轻量级设计

📦 安装

# npm
npm install @bugfix2019/request-middleware

# pnpm
pnpm add @bugfix2019/request-middleware

# yarn
yarn add @bugfix2019/request-middleware

🚀 快速开始

import axios from 'axios';
import { 
  createMiddlewareEngine, 
  fromAxios, 
  createLoggerMiddleware 
} from '@bugfix2019/request-middleware';

// 创建 axios 实例
const axiosInstance = axios.create({
  baseURL: 'https://api.example.com',
});

// 创建中间件引擎
const engine = createMiddlewareEngine({
  adapter: fromAxios(axiosInstance),
  defaults: {
    timeout: 10000,
    headers: {
      'Content-Type': 'application/json',
    },
  },
});

// 注册日志中间件
engine.use(createLoggerMiddleware({
  level: 'info',
  logRequestBody: true,
}));

// 发送请求
const response = await engine.get<{ id: string; name: string }>('/users/1');
console.log(response.data);

🧅 中间件机制

中间件采用洋葱模型,请求会依次通过所有中间件,响应则按相反顺序返回:

请求 → [中间件1] → [中间件2] → [中间件3] → 实际请求
响应 ← [中间件1] ← [中间件2] ← [中间件3] ← 实际响应

编写自定义中间件

import type { Middleware } from '@bugfix2019/request-middleware';

const myMiddleware: Middleware = async (ctx, next) => {
  // 请求前处理
  console.log('请求开始:', ctx.request.url);
  ctx.setMeta('customData', { startTime: Date.now() });

  await next(); // 调用下一个中间件

  // 响应后处理
  const customData = ctx.getMeta<{ startTime: number }>('customData');
  console.log('请求完成, 耗时:', Date.now() - customData!.startTime, 'ms');
};

engine.use(myMiddleware);

上下文 (Context)

每个请求都有一个 ctx 对象,包含请求的完整生命周期信息:

interface RequestContext<TReqData, TResData> {
  // 请求配置
  request: RequestConfig<TReqData>;
  
  // 响应对象 (响应阶段可用)
  response?: Response<TResData>;
  
  // 错误对象 (发生错误时可用)
  error?: Error;
  
  // 时间信息
  startTime: number;
  endTime?: number;
  duration?: number;
  
  // 请求状态: 'pending' | 'sending' | 'success' | 'error' | 'aborted'
  state: RequestState;
  
  // 元数据操作
  meta: ContextMeta;
  setMeta: <T>(key: string, value: T) => void;
  getMeta: <T>(key: string) => T | undefined;
  
  // 中止控制
  abort: () => void;
  aborted: boolean;
}

📦 官方中间件

Logger 日志中间件

import { createLoggerMiddleware } from '@bugfix2019/request-middleware';

const logger = createLoggerMiddleware({
  level: 'info',           // 日志级别: 'debug' | 'info' | 'warn' | 'error' | 'silent'
  logRequestBody: true,    // 是否记录请求体
  logResponseBody: false,  // 是否记录响应体
  logHeaders: false,       // 是否记录请求头
  logger: customLogger,    // 自定义日志输出器
});

engine.use(logger);

更多中间件 (即将推出)

  • createRetryMiddleware - 请求重试
  • createCacheMiddleware - 请求缓存
  • createErrorHandlerMiddleware - 错误处理

🔧 配置请求拦截器和响应拦截器

对于 Fetch 适配器,您可以配置请求拦截器和响应拦截器来修改请求配置或响应数据:

import { createMiddlewareEngine, createFetchAdapter } from '@bugfix2019/request-middleware';

// 创建带有拦截器的 Fetch 适配器
const adapter = createFetchAdapter({
  baseURL: 'https://api.example.com',
  interceptors: {
    // 请求拦截器:在发送请求前修改配置
    request: (config) => {
      console.log('发送请求:', config.url);
      // 添加认证头
      return {
        ...config,
        headers: {
          ...config.headers,
          'Authorization': 'Bearer ' + getToken(),
        },
      };
    },
    // 响应拦截器:在接收响应后修改数据
    response: (response) => {
      console.log('接收响应:', response.status);
      // 处理响应数据
      return {
        ...response,
        data: transformResponseData(response.data),
      };
    },
  },
});

// 创建中间件引擎
const engine = createMiddlewareEngine({
  adapter,
});

拦截器函数可以是同步的或异步的(返回 Promise)。

🔄 EventSource 支持

request-middleware 支持使用 @microsoft/fetch-event-source 进行 Server-Sent Events (SSE) 连接:

import { createMiddlewareEngine, createEventSourceAdapter } from '@bugfix2019/request-middleware';

// 创建 EventSource 适配器
const adapter = createEventSourceAdapter({
  baseURL: 'https://api.example.com',
  onMessage: (event) => {
    console.log('收到消息:', event.data);
  },
  onOpen: (response) => {
    console.log('连接已打开,状态:', response.status);
  },
  onError: (error) => {
    console.error('连接错误:', error);
  },
  onClose: () => {
    console.log('连接已关闭');
  },
});

// 创建中间件引擎
const engine = createMiddlewareEngine({
  adapter,
});

// 发起 SSE 连接
const response = await engine.get('/events');

EventSource 适配器适用于需要实时数据流的场景,如聊天应用、实时通知等。

🔧 API 参考

createMiddlewareEngine(config)

创建中间件引擎实例。

const engine = createMiddlewareEngine({
  adapter: fromAxios(axiosInstance), // 请求适配器
  defaults: {                         // 默认请求配置
    timeout: 10000,
    headers: { 'X-Custom': 'value' },
  },
});

engine.use(middleware)

注册中间件。

engine.use(myMiddleware);
engine.useAll(middleware1, middleware2, middleware3);

engine.request(config)

发送请求。

const response = await engine.request({
  url: '/api/users',
  method: 'GET',
  params: { page: 1 },
});

快捷方法

engine.get<TResData>(url, config?)
engine.post<TReqData, TResData>(url, data?, config?)
engine.put<TReqData, TResData>(url, data?, config?)
engine.delete<TResData>(url, config?)
engine.patch<TReqData, TResData>(url, data?, config?)

🧪 测试覆盖率

| 文件 | 语句覆盖率 | 分支覆盖率 | 函数覆盖率 | 行覆盖率 | |------|-----------|-----------|-----------|---------| | 总计 | 69.27% | 85.32% | 80.48% | 69.27% | | src/index.ts | 0% | 0% | 0% | 0% | | adapters/fetch.ts | 96.65% | 82.92% | 100% | 96.65% | | adapters/eventSource.ts | 81.29% | 81.81% | 50% | 81.29% | | adapters/axios.ts | 100% | 100% | 100% | 100% | | adapters/index.ts | 0% | 0% | 0% | 0% | | client/httpClient.ts | 98.8% | 86.66% | 100% | 98.8% | | client/index.ts | 0% | 0% | 0% | 0% | | engine/compose.ts | 97.8% | 95.23% | 100% | 97.8% | | engine/middlewareEngine.ts | 100% | 100% | 100% | 100% | | engine/index.ts | 100% | 100% | 100% | 100% | | engine/middlewareTypes.ts | 0% | 0% | 0% | 0% |


📂 项目结构

request-middleware/
├── src/
│   ├── core/               # 核心中间件引擎
│   │   ├── engine.ts       # MiddlewareEngine 类
│   │   └── index.ts
│   ├── middlewares/        # 官方中间件
│   │   ├── logger.ts       # 日志中间件
│   │   └── index.ts
│   ├── adapters/           # 请求适配器
│   │   ├── axios.ts        # Axios 适配器
│   │   ├── fetch.ts        # Fetch 适配器
│   │   ├── eventSource.ts  # EventSource 适配器
│   │   └── index.ts
│   ├── types/              # TypeScript 类型定义
│   │   └── index.ts
│   └── index.ts            # 入口文件
├── tests/                  # 测试文件
├── dist/                   # 构建输出
├── package.json
├── tsconfig.json
├── tsup.config.ts          # 构建配置
└── README.md

🛠️ 开发

# 安装依赖
pnpm install

# 开发模式
pnpm run dev

# 构建
pnpm run build

# 运行测试
pnpm test

# 查看覆盖率
pnpm test -- --coverage

📦 发布到 npm

# 1. 确保构建成功
pnpm run build

# 2. 确保测试通过
pnpm test -- --run

# 3. 更新版本号
npm version patch  # 1.0.0 -> 1.0.1

# 4. 发布
npm publish --access public

📄 许可证

MIT

👥 贡献者

感谢以下贡献者对本项目的贡献:

🔗 相关链接


❓ 常见问题

Q: 如何在项目中使用?

A: 直接在项目中引入 request-middleware 并结合 axios/fetch 适配器即可,无需特殊配置。

Q: 如何自定义中间件?

A: 参考文档中的"编写自定义中间件"示例,实现 (ctx, next) => Promise<void> 结构即可。

Q: 如何查看测试覆盖率?

A: 运行 pnpm test -- --coverage 查看详细覆盖率报告。

Q: 如何贡献代码?

A: Fork 仓库,提交 PR,确保测试覆盖率 100%。


🙏 致谢

感谢所有为本项目做出贡献的开发者!查看完整的贡献者列表


Made with ❤️ by Polaris