Node.js连接提前终止,CSV导入PostgreSQL仅插入首行问题排查
CSV文件数据插入PostgreSQL时连接提前终止问题
背景
我是Node.js新手,已在Windows Server上搭建Node/Express服务器,对接PostgreSQL数据库。需求是通过HTML表单让用户上传本地CSV文件,并将文件数据插入数据库。
现有代码
app.post('/envoi', upload.single("fichiercsv"), async(req, res) => { let newClient try { const { identifiant, motdepasse } = req.body const clientConfigModifie = { ...clientConfigDefaut, user: identifiant, password: '' } newClient = new Client(clientConfigModifie) await newClient.connect() const rows = [] const buffer = req.file.buffer // console.log(buffer) //ok const readableStreamFromBuffer = new stream.Readable() readableStreamFromBuffer.push(req.file.buffer) readableStreamFromBuffer.push(null) await newPromise( (resolve, reject) => { fastcsv.parseStream(readableStreamFromBuffer, { headers: false }) .on('data', us => { rows.push(us) }) .on('end', async() => { rows.shift() const usTotal = rows.map( us => us.join("").split(";")) // console.log(us) for (const us of usTotal) { await newClient.query("insert into activite.us (numus, gidgeo) VALUES ($1, $2)", [us[0], us[13]]) }) resolve() }) .on("error", error => console.error(error)) }) } catch(e) { console.log("erreur lors du traitement", e) res.send(`<h3>échec de la connexion</h3>`) } finally { try { newClient.end() } catch(e) { console.log(e) } } })
问题情况
- 若省略finally代码块,数据可全部插入数据库,但数据库连接会持续运行;
- 添加finally代码块后,仅能插入us的第一行数据,且报错:
error: Connection terminated at C:\Apache\balbla\
此时newClient.query仅执行一次,连接就莫名终止但未正常关闭,请问我哪里操作有误?
*编辑:已根据@I2yscho的回答更新代码。
问题原因及修正方案
你的代码存在三个关键问题,导致连接提前终止:
- Promise拼写错误:代码中
newPromise应为new Promise,缺少空格会导致无法正确创建异步等待的Promise,使得后续逻辑没有等待CSV解析完成就进入finally块。 - 语法错误导致提前resolve:在
end事件的回调中,for循环后面多写了一个}),这会让resolve()在第一个插入操作完成后就被执行,await Promise提前结束,finally块立刻关闭数据库连接,后续插入操作因此失败。 - 解析错误未捕获:fastcsv的
error事件仅打印错误但未调用reject,导致Promise无法感知解析失败,可能隐藏潜在问题。
修正后的代码
app.post('/envoi', upload.single("fichiercsv"), async(req, res) => { let newClient try { const { identifiant, motdepasse } = req.body const clientConfigModifie = { ...clientConfigDefaut, user: identifiant, password: '' // 若需使用用户提交的密码,请改为motdepasse } newClient = new Client(clientConfigModifie) await newClient.connect() const rows = [] const buffer = req.file.buffer const readableStreamFromBuffer = new stream.Readable() readableStreamFromBuffer.push(req.file.buffer) readableStreamFromBuffer.push(null) await new Promise( (resolve, reject) => { fastcsv.parseStream(readableStreamFromBuffer, { headers: false }) .on('data', us => { rows.push(us) }) .on('end', async() => { rows.shift() // 移除CSV表头行 const usTotal = rows.map( us => us.join("").split(";")) // 遍历所有数据行执行插入,确保全部完成后再resolve for (const us of usTotal) { await newClient.query("insert into activite.us (numus, gidgeo) VALUES ($1, $2)", [us[0], us[13]]) } resolve() }) .on("error", error => { console.error(error) reject(error) // 解析出错时拒绝Promise,让外层catch捕获 }) }) } catch(e) { console.log("处理过程出错", e) res.send(`<h3>连接或处理失败</h3>`) } finally { if (newClient) { // 确保newClient已初始化再尝试关闭 try { await newClient.end() // 等待连接关闭完成 } catch(e) { console.log("关闭连接时出错", e) } } } })
额外优化建议
- 批量插入提升性能:当前循环执行单条插入效率较低,建议使用PostgreSQL批量插入语法(如
INSERT INTO ... VALUES (...), (...), ...),减少数据库交互次数。 - 密码正确传递:代码中
password: ''固定为空,若需使用用户提交的密码,应改为password: motdepasse。 - 流式处理减少内存占用:当前先将所有行存入
rows数组再处理,若CSV文件较大会占用大量内存,建议直接在data事件中处理单条数据或批量积累后插入,无需全部存入内存。
内容的提问来源于stack exchange,提问作者Leehan
相关产品推荐
相关产品推荐

