Express服务器无法异步处理并发API请求(需等待旧请求完成)
MEVN栈后端请求阻塞问题排查
问题概述
我基于MEVN栈(MongoDB、Express、VueJS、Node)开发首个Web应用,按预期Node.js的请求处理应该是异步非阻塞的,但实际所有请求都会被阻塞,必须等前一个请求处理完成才能响应下一个。比如用户通过POST上传数据时,其他用户的GET请求会完全挂起,直到POST操作结束。
测试验证
我做了如下测试:
- 访问服务器的
/test路由(该路由包含5秒延迟) - 同时用Postman调用
/api路由
结果Postman的请求会一直挂起,直到/test路由的延迟结束后才会得到响应。
相关代码片段
server.js头部代码
// Importing required modules const bodyParser = require('body-parser'); const cors = require('cors'); const express = require('express'); const morgan = require('morgan'); const multer = require('multer'); const hashlips = require('./src/main.js') const fs = require('fs-extra'); // parse env variables require('dotenv').config(); require("./helpers/db/mongodb.js")(); // Configuring port const port = process.env.PORT || 9000; //configure express const app = express(); // Configure middlewares app.use(cors()); app.use(express.json({ limit: '10mb' })); app.use(morgan('dev')); app.use(bodyParser.json({ limit: '10mb' })); app.use(express.urlencoded({extended: true}, { limit: '10mb' })); app.set('view engine', 'html'); // Static folder app.use(express.static(__dirname + '/views/')); // Defining route middleware app.use('/api', require('./routes/api')); //routes app.get('/test', (req, res) => { await new Promise(r => setTimeout(r, 5000)); res.send("<h3>Express Server") })
api.js路由代码
const express = require('express'); const { //init CRUD createData, readData, updateData, deleteData, deleteAllData, //init register login registerNewUser, loginUser, getUserDetails, //init collection saving createCollection, readCollectionData, deleteAllCollections, deleteCollection, updateCollection, } = require('../controllers/user_controller'); const auth = require('../config/auth') const router = express.Router(); router .put("/collection", createCollection) .put("/collectionu", updateCollection) .post("/", createData) .post("/register", registerNewUser) .post("/login", loginUser) .get("/collection", readCollectionData) .get("/me", auth, getUserDetails) .get('/', readData) .put('/:id', updateData) .delete('/deletecollections', deleteAllCollections) .delete('/deleteall', deleteAllData) .delete('/deletecollection/:id', auth, deleteCollection) .delete('/:id', deleteData); module.exports = router;
同步API警告堆栈跟踪
启动时添加--trace-sync-io参数得到以下堆栈信息:
(node:62551) WARNING: Detected use of sync API at pbkdf2Sync (node:internal/crypto/pbkdf2:80:37) at HI (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/auth/scram.js:245:31) at continueScramConversation (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/auth/scram.js:138:28) at /home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/auth/scram.js:90:9 at onMessage (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/connection.js:222:9) at /home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/connection.js:63:60 at emit (node:events:394:28) at processIncomingData (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/message_stream.js:132:20) at _write (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/message_stream.js:33:9) at writeOrBuffer (node:internal/streams/writable:389:12) Connected to MongoDB (node:62551) WARNING: Detected use of sync API at randomFillSync (node:internal/crypto/random:137:19) at randomBytes (node:internal/crypto/random:99:5) at uuidV4 (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/utils.js:439:27) at ServerSession (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/sessions.js:541:62) at acquire (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/sessions.js:619:16) at get serverSession (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/sessions.js:94:46) at applySession (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/sessions.js:670:35) at command (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/connection.js:278:53) at /home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/sdam/server.js:210:18 at /home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongodb/lib/cmap/connection_pool.js:271:13 (node:62551) WARNING: Detected use of sync API at randomFillSync (node:internal/crypto/random:137:19) at randomBytes (node:internal/crypto/random:99:5) at ObjectId.generate (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/bson/lib/objectid.js:145:54) at ObjectId (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/bson/lib/objectid.js:47:34) at NativeCollection.<computed> (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js:84:18) at create (/home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongoose/lib/model.js:1803:22) at /home/zach/Documents/WebProjects/mevn/ezmode/server/node_modules/mongoose/lib/model.js:1764:7 at processTicksAndRejections (node:internal/process/task_queues:78:11)
问题分析与解决建议
核心原因
Node.js是单线程事件循环模型,一旦出现同步阻塞API调用,会直接卡住整个事件循环,导致所有后续请求无法被处理。从堆栈跟踪可以看到,MongoDB驱动底层使用了多个同步API:
pbkdf2Sync:SCRAM认证时的同步密钥派生randomFillSync:生成UUID和ObjectId时的同步随机数生成
这些同步操作是导致请求阻塞的根本原因。另外你的/test路由代码存在语法错误:回调函数没有声明为async就使用await,会直接抛出异常,也可能影响测试结果。
解决步骤
修复/test路由语法错误
给路由回调添加async关键字,确保异步延迟不会阻塞:app.get('/test', async (req, res) => { await new Promise(r => setTimeout(r, 5000)); res.send("<h3>Express Server</h3>") })这个路由本身是异步非阻塞的,修复后可以单独验证Node.js的异步处理能力。
升级MongoDB驱动与Mongoose
旧版本的MongoDB驱动可能存在同步阻塞调用,升级到最新稳定版可以避免这类问题:npm install mongodb@latest mongoose@latest确保MongoDB连接使用异步方式
检查helpers/db/mongodb.js,改用异步连接:const mongoose = require('mongoose'); module.exports = async () => { try { await mongoose.connect(process.env.MONGODB_URI); console.log('Connected to MongoDB'); } catch (error) { console.error('MongoDB connection failed:', error); } };避免所有同步API调用
检查代码中是否使用了其他Sync后缀的API(比如fs.readFileSync),全部替换为异步版本(比如fs.promises.readFile)。
内容的提问来源于stack exchange,提问作者Zach Hopkins
相关产品推荐
相关产品推荐

