讲师中心 微信公众号

工具推荐

视频效率加速
updream

一键生成高质量推广成片

Laper
Laper

剧本策划到成片协作

立刻MV
立刻MV

低成本歌曲 MV、视频生成

剧云
剧云

中文短剧剧本制作平台

Node.js Express应用中通用追踪未完成HTTP请求的方法

酷婷吖_6316

酷婷吖_6316

发布时间:2025-11-16 19:39:00

|

720人浏览过

|

来源于php中文网

原创

Node.js Express应用中通用追踪未完成HTTP请求的方法

本教程旨在解决node.js express应用中难以通用追踪“运行中进程”或“活动promise”的问题,特别是针对未完成的http请求。我们将介绍如何利用`on-finished`中间件来建立一个通用的请求生命周期监控机制,从而无需为每个异步路由单独编写状态检查逻辑,实现对当前未响应请求数量的实时统计。

在构建复杂的Node.js应用时,尤其是在使用Express框架处理大量异步HTTP请求的场景下,我们常常需要了解当前有多少请求正在被处理,或者有多少异步操作尚未完成。直接监控Node.js内部的Promise状态或操作系统层面的进程通常不切实际且过于复杂。更实际的需求是追踪那些已经接收但尚未完全响应的HTTP请求。本教程将提供一个通用且高效的方法来解决这一问题,避免为每个业务逻辑编写冗余的状态管理代码。

理解问题核心:追踪未完成的HTTP请求

“运行中的进程”或“活动的Promise”在HTTP服务上下文中,通常指的是那些已经进入服务器处理流程,但其HTTP响应尚未发送给客户端的请求。这些请求可能正在执行数据库查询、调用外部API或进行其他耗时操作。手动为每个异步路由添加开始和结束标志来更新全局计数器,不仅工作量巨大,而且容易出错。我们需要一个能够自动挂钩到HTTP请求生命周期的机制。

解决方案:利用 on-finished 中间件

Node.js生态系统提供了on-finished这个轻量级中间件,它专门用于监听HTTP请求或响应的完成事件。通过在请求开始时记录请求,并在响应完成时移除记录,我们就可以精确地追踪当前有多少请求处于“进行中”状态。

1. 安装 on-finished

首先,确保你的项目中安装了on-finished库:

npm install on-finished

2. 创建请求追踪中间件

我们将创建一个自定义的Express中间件,它会维护一个全局的Set来存储当前所有未完成请求的唯一标识符。

const onFinished = require('on-finished');

// 使用 Set 存储未完成请求的唯一ID
const unresolvedRequestIds = new Set();

/**
 * 请求追踪中间件
 * 在请求开始时添加ID,在响应结束时移除ID。
 */
const requestTracker = (req, res, next) => {
  // 为每个请求生成一个唯一的ID
  // 实际应用中可以使用更健壮的ID生成策略,如 UUID
  const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  unresolvedRequestIds.add(id);

  // 监听响应完成事件
  onFinished(res, () => {
    unresolvedRequestIds.delete(id);
    console.log(`Request finished. Active requests: ${unresolvedRequestIds.size}`);
  });

  next(); // 继续处理请求
};

代码解释:

  • unresolvedRequestIds:一个JavaScript Set,用于存储每个未完成请求的唯一标识符。Set的特性是只存储唯一值,并且查找和删除效率高。
  • id = Math.random()...:这里使用了一个简单的随机字符串作为请求ID。在生产环境中,你可能需要一个更健壮的唯一ID生成器,例如UUID(uuid库)。
  • onFinished(res, () => { ... }):这是核心逻辑。当HTTP响应(res)完成(无论是成功发送、客户端中断还是发生错误)时,回调函数会被执行,此时我们将对应的请求ID从unresolvedRequestIds中移除。
  • next():调用next()将请求传递给下一个中间件或路由处理器。

3. 集成请求追踪中间件

你可以选择在特定路由上应用此中间件,或者在整个应用程序级别应用。

A. 针对特定路由应用

Expanso yaml-to-json
Expanso yaml-to-json

使用 Expanso Edge 管道将 YAML 输入转换为 JSON 格式。

下载

如果你只想追踪某些特定的异步路由,可以在这些路由前使用requestTracker:

const express = require('express');
const app = express();
const router = express.Router();

// 引入上面定义的 requestTracker
// const requestTracker = ...;

router.post('/someEndpoint', requestTracker, async (req, res) => {
  console.log('Processing /someEndpoint...');
  // 模拟异步操作
  await new Promise(resolve => setTimeout(resolve, 2000));
  res.status(200).json({ message: 'Operation completed' });
});

router.get('/anotherEndpoint', requestTracker, async (req, res) => {
  console.log('Processing /anotherEndpoint...');
  await new Promise(resolve => setTimeout(resolve, 1000));
  res.status(200).json({ message: 'Another operation completed' });
});

app.use('/', router); // 将路由挂载到应用

B. 全局应用

更常见且更方便的做法是在应用程序的顶层应用requestTracker。这样,它将对所有进入Express应用的请求生效。

const express = require('express');
const app = express();

// 引入上面定义的 requestTracker
// const requestTracker = ...;

// 在所有路由之前应用请求追踪中间件
app.use(requestTracker);

app.post('/someEndpoint', async (req, res) => {
  console.log('Processing /someEndpoint...');
  await new Promise(resolve => setTimeout(resolve, 2000));
  res.status(200).json({ message: 'Operation completed' });
});

app.get('/anotherEndpoint', async (req, res) => {
  console.log('Processing /anotherEndpoint...');
  await new Promise(resolve => setTimeout(resolve, 1000));
  res.status(200).json({ message: 'Another operation completed' });
});

// 其他路由...

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

注意事项: 当全局应用requestTracker时,它会追踪所有HTTP请求,包括那些不涉及复杂异步操作的简单请求(如静态文件请求或同步路由)。这通常是可接受的,因为它提供了一个全面的视图。

4. 创建获取未完成请求数量的API

现在,我们可以创建一个新的API端点,用于暴露当前未完成请求的数量。

// ... (之前的 requestTracker 和 app.use(requestTracker) 代码) ...

app.get('/getUnresolvedRequestCount', (req, res) => {
   res.status(200).json({ unresolvedRequestCount: unresolvedRequestIds.size });
});

// ... (其他路由和 app.listen) ...

当你访问 /getUnresolvedRequestCount 时,它将返回一个JSON对象,其中包含当前正在处理的HTTP请求数量。

完整示例代码

const express = require('express');
const onFinished = require('on-finished');
const app = express();
const PORT = 3000;

// 使用 Set 存储未完成请求的唯一ID
const unresolvedRequestIds = new Set();

/**
 * 请求追踪中间件
 * 在请求开始时添加ID,在响应结束时移除ID。
 */
const requestTracker = (req, res, next) => {
  // 为每个请求生成一个唯一的ID
  const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  unresolvedRequestIds.add(id);
  console.log(`Request started [${id}]. Active requests: ${unresolvedRequestIds.size}`);

  // 监听响应完成事件
  onFinished(res, () => {
    unresolvedRequestIds.delete(id);
    console.log(`Request finished [${id}]. Active requests: ${unresolvedRequestIds.size}`);
  });

  next(); // 继续处理请求
};

// 在所有路由之前应用请求追踪中间件
app.use(requestTracker);

// 示例异步路由 1
app.post('/api/long-task', async (req, res) => {
  console.log('Processing /api/long-task...');
  // 模拟一个耗时5秒的异步操作
  await new Promise(resolve => setTimeout(resolve, 5000));
  res.status(200).json({ message: 'Long task completed successfully!' });
});

// 示例异步路由 2
app.get('/api/short-task', async (req, res) => {
  console.log('Processing /api/short-task...');
  // 模拟一个耗时1秒的异步操作
  await new Promise(resolve => setTimeout(resolve, 1000));
  res.status(200).json({ message: 'Short task completed successfully!' });
});

// 获取未完成请求数量的API
app.get('/getUnresolvedRequestCount', (req, res) => {
   res.status(200).json({ unresolvedRequestCount: unresolvedRequestIds.size });
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
  console.log(`Try POST http://localhost:${PORT}/api/long-task`);
  console.log(`Try GET http://localhost:${PORT}/api/short-task`);
  console.log(`Monitor GET http://localhost:${PORT}/getUnresolvedRequestCount`);
});

总结与注意事项

  • 通用性: 这种方法提供了一个通用的机制来监控HTTP请求的生命周期,而无需修改每个业务路由的逻辑。
  • 粒度: 这种方法追踪的是HTTP请求,而不是Node.js应用程序中所有的Promise或底层进程。对于大多数Web服务监控场景,追踪HTTP请求是更直接和有用的指标。
  • 资源消耗: Set数据结构在添加、删除和检查大小方面效率很高,因此这种方法对性能的影响很小。
  • 扩展性: 你可以扩展requestTracker中间件,不仅仅存储请求ID,还可以存储更多信息,例如请求路径、开始时间、用户ID等,以便进行更详细的监控和分析。
  • 唯一ID生成: 示例中使用了Math.random()生成ID,这在小规模测试中可行,但在生产环境中建议使用更健壮的唯一标识符生成器(如uuid库),以避免ID冲突的极小概率。
  • 错误处理: on-finished库能够正确处理请求正常完成、客户端中断连接或服务器内部错误等多种情况,确保请求ID在任何情况下都能被正确移除。

通过上述方法,你可以为你的Node.js Express应用建立一个可靠的、通用的未完成HTTP请求监控系统,从而更好地了解应用的实时负载和处理能力。

热门AI工具

更多
SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

729

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

664

2025.12.18

ThinkPHP中间件机制与请求拦截处理实践
ThinkPHP中间件机制与请求拦截处理实践

本专题围绕 ThinkPHP 中间件体系展开,深入讲解中间件的定义、注册与执行流程。内容包括全局中间件与路由中间件的区别、请求前后处理逻辑、自定义中间件开发以及权限验证与日志处理应用。通过实际案例,帮助开发者掌握中间件在项目中的核心作用与最佳实践。

458

2026.03.31

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2315

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

3802

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

1256

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

4419

2025.09.10

Node.js后端开发与Express框架实践
Node.js后端开发与Express框架实践

本专题针对初中级 Node.js 开发者,系统讲解如何使用 Express 框架搭建高性能后端服务。内容包括路由设计、中间件开发、数据库集成、API 安全与异常处理,以及 RESTful API 的设计与优化。通过实际项目演示,帮助开发者快速掌握 Node.js 后端开发流程。

781

2026.02.10

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

0

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 12.5万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn