React+Node.js+MariaDB架构下执行数据库更新后后端随机挂起问题求助
核心问题原因
你遇到的服务挂起最核心的诱因是POST接口处理完成后没有给客户端返回任何响应,HTTP请求会一直处于挂起状态:
- 浏览器对同域名的并发请求数有默认限制(一般为6个),几次点击操作产生的POST请求全部挂起后,后续的轮询GET请求会进入浏览器的待发送队列完全卡住
- 未关闭的请求也会持续占用Node服务和数据库连接池的连接资源,最终导致服务无响应
- 重启服务时所有挂起的连接被强制断开,队列中积压的请求集中执行,才会出现日志批量打印的情况
其他需要修复的风险点
- 两个接口的异常捕获逻辑直接
throw err,没有返回错误响应,遇到数据库操作异常时同样会导致请求挂起 - POST接口直接拼接SQL字符串,存在严重的SQL注入风险
- 前端用固定间隔
setInterval轮询,不感知上一个请求是否完成,网络延迟高时会出现请求堆积 - 前端
getSelPos方法中打印的selPos变量未定义,会抛出未捕获异常
修复后的代码
Node后端修改
const express = require('express') const db = require('./db') const app = express() const port = 5000 const bodyParser = require("body-parser"); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); next(); }); // GET接口修复:异常时返回错误响应 app.get('/selector', async (req, res) => { try { const result = await db.pool.query("select value from db.tags where tag='1006'"); res.send(result[0].value.toString()); console.log(result[0].value.toString()); } catch (err) { console.error(err); res.status(500).send('查询失败'); } }); // POST接口修复:新增响应返回、使用参数化查询防注入 app.post('/selector', async (req, res) => { try { // 不同数据库驱动的参数化查询写法略有差异,可根据你用的驱动适配 const result = await db.pool.query("update db.tags set value = ? where tag='1006'", [req.body.position]); console.log(result); res.send('更新成功'); // 必须返回响应结束本次请求 } catch (err) { console.error(err); res.status(500).send('更新失败'); } }); app.listen(port, () => console.log(`Listening on port ${port}`));
React前端修改
// 改成动态轮询,等上一次请求完成后再触发下一次,避免请求堆积 componentDidMount() { this.pollingEnabled = true; this.runPolling(); } componentWillUnmount() { this.pollingEnabled = false; if (this.pollingTimer) clearTimeout(this.pollingTimer); } runPolling() { if (!this.pollingEnabled) return; this.getSelPos().finally(() => { this.pollingTimer = setTimeout(() => this.runPolling(), 2000); }) } getSelPos() { return axios.get("http://localhost:5000/selector", { crossdomain: true }).then(response => { console.log(response.data); this.setState({SelectorPos: parseInt(response.data)}, () => { // 确保state更新完成后再打印 console.log("Selpos is" + this.state.SelectorPos); }); }).catch(err => { console.error('获取位置失败', err); }); } setSelPos(i) { axios.post("http://localhost:5000/selector", { position: i }).then((response) => { console.log(response); }, (error) => { console.log(error); }); } handleClick(i){ this.setSelPos(i); }
额外优化建议
检查你的数据库连接池配置,建议将最大连接数调整到10~20,避免并发请求多时连接不够用。
内容的提问来源于stack exchange,提问作者Cm1602
相关产品推荐
相关产品推荐

