React+Node服务GET请求前几次正常后报socket hang up、代理错误
GET请求前几次正常后续失败问题排查
基础环境与初始现象
- 技术栈:React v16.8.6、Node v12.16.2
- 初始问题:本地与云服务器环境测试时,fetch发起的GET请求前2~3次可正常响应,后续请求直接失败。
问题复现与补充测试结果
- Postman测试云服务器接口:所有GET接口(含
/usr-info、/some-other-info、/another-info等)前几次可正常返回,之后抛出Error: socket hang up错误 - 本地环境测试:同类请求耗时较长(约1~2分钟)但最终可正常返回
- 浏览器直连测试:地址栏输入
cloud_ip:4200/usr-info访问,前几次正常,多次刷新后返回ERR_EMPTY_RESPONSE,与之前现象一致 - 页面交互表现:
- 执行登录、退出操作23次后,本地环境登录按钮会禁用12分钟,云服务器环境永久处于禁用状态
- 按钮禁用时提交账号密码,会因
dbUserInfo为null无法匹配对应用户信息,抛出undefined错误 - 报错后刷新页面触发代理错误:
Proxy error: Could not proxy request /usr-info from localhost(or cloud public ip):3000 to localhost(or cloud public ip):4200.
相关代码
1. package.json配置
{ ... "proxy": "https://localhost (or cloud public ip):4200", ... "scripts": { "start": "env-cmd -f .env.development react-app-rewired start", "run": "env-cmd -f .env.development node server/index.js", "start:prod": "env-cmd -f .env.production react-app-wired start", "run:prod": "env-cmd -f .env.production node server/index.js" } }
2. login.jsx核心逻辑
const login = () => { const [dbUserInfo, setDbUserInfo] = useState([]); const getData = async (route) => { // 校验登录信息后拉取用户信息及其他数据 const response = await fetch(route); return response.json(); } useEffect(() => { // setLoading仅用于测试,控制登录按钮禁用状态 setLoading(true) getData('/usr-info').then((res) => { setDbUserInfo(res); setLoading(false); }).catch(error => console.log(error)); }, []); ... }
3. 服务端index.js核心逻辑
const express = require('express'); const mysql = require('mysql'); const conn = mysql.createPool({ host: host, user: user, password: password, database: 'database' }) const app = express(); app.use(express.json()); app.get('/usr-info', function (req, res) { conn.getConnection(function (err, connection) { connection.query('SELECT * from TABLE where COL = "VAL1"', function (error,results, fields) { if (error) throw error; res.send(results) }); }); }); app.listen(4200, () => { console.log('server started on 4200') })
已尝试方案
- 已确认服务端接口配置了
res.send返回逻辑 - 尝试在
handleSubmit方法中添加event.preventDefault(),未解决问题 - 初步怀疑3000端口客户端到4200端口服务端的前序请求未释放导致服务异常,无法定位根因
根因定位
核心问题出在服务端MySQL连接池的使用逻辑:
调用conn.getConnection()从连接池获取连接后,执行完查询操作没有主动释放连接归还到连接池。几次请求后连接池的所有可用连接会被完全占满,后续请求无法获取到可用数据库连接,就会出现请求挂起、超时、socket hang up的现象,和测试表现完全吻合:
- 本地环境等待1~2分钟后MySQL主动断开空闲连接,连接被回收后请求可正常响应
- 云服务器环境网络代理超时时间更短,请求直接被断开返回错误
另外package.json中proxy配置为https://前缀,如果服务端Express没有配置HTTPS证书,也可能引发偶发的连接异常。
修复方案
- 修改服务端接口逻辑,查询完成后无论成功失败都主动释放数据库连接,同时补充错误处理逻辑,修复后代码如下:
app.get('/usr-info', function (req, res) { conn.getConnection(function (err, connection) { // 处理获取连接失败场景 if (err) { console.error('获取数据库连接失败:', err); return res.status(500).send({msg: '服务内部错误'}); } connection.query('SELECT * from TABLE where COL = "VAL1"', function (error, results, fields) { // 查询执行完先释放连接 connection.release(); if (error) { console.error('数据查询失败:', error); return res.status(500).send({msg: '数据查询失败'}); } res.send(results) }); }); });
- 优化MySQL连接池配置,根据服务器性能调整最大连接数:
const conn = mysql.createPool({ host: host, user: user, password: password, database: 'database', connectionLimit: 20 // 按需调整,默认值为10 })
- 检查服务端是否开启HTTPS,若仅使用HTTP协议,将package.json中proxy配置修改为
http://localhost:4200即可。
内容的提问来源于stack exchange,提问作者beginnercoder
相关产品推荐
相关产品推荐

