登录后/index路由HTTP请求持续Pending问题求助
问题描述
登录验证通过后跳转至/index?user_name=xxx&password=xxx时,该路由请求始终处于Pending状态。已知登录函数entrar()可正常验证数据库中的用户名和密码,返回状态码200。
前端登录函数代码
async function entrar() { const user_name = document.getElementById('user_name').value.trim(); const password = document.getElementById('password').value.trim(); try { const response = await fetch('/user/search', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `user_name=${encodeURIComponent(user_name)}&password=${encodeURIComponent(password)}` }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const objJson = await response.json(); if (objJson && objJson.user_name === user_name && objJson.password === password) { localStorage.setItem('objJson', JSON.stringify(objJson)); window.location.href = `/index?user_name=${encodeURIComponent(user_name)}&password=${encodeURIComponent(password)}`; } else { window.location.href = '/login'; } } catch (error) { console.error('Error fetching data:', error); window.location.href = '/login'; // Redirect to login page on error } }
后端/index路由代码
app.get('/index', urlencodedParser, async function(req, res){ let objJson = {}; if(req.query.user_name) objJson.user_name = req.query.user_name; else objJson.user_name = false; if(req.query.password) objJson.password = req.query.password; else objJson.password = false; findUserOne(objJson, async function(result){ if((result)&&(result.activate==true)){ res.set('Content-Type', 'text/html'); const data = await fs.readFileSync('./index.html','utf8'); await res.send(data); }else{ res.set('Content-Type', 'text/html'); const data = await fs.readFileSync('./login.html','utf8'); await res.send(data); } }); });
登录表单代码
<div class="container"> <h2 align="center">LOGIN</h2> <br> <center> <div align="center" style="width:30%;"> <input type="text" id="user_name" class="form-control" placeholder="Nome de usuário"><br> <input type="password" id="password" class="form-control" placeholder="Senha"><br> <br> <button class="btn btn-lg btn-info" onclick="entrar()">Entrar</button> </div> </center> </div>
问题分析与解决
核心问题
后端/index路由中,findUserOne的回调函数被标记为async,但fs.readFileSync是同步IO操作,加await会导致异步上下文混乱;同时回调函数的异步逻辑可能未正确触发响应结束,导致请求一直处于Pending状态。
另外存在两个高风险安全问题:
- 跳转时将密码放在URL参数中,会暴露在地址栏、日志和浏览器历史中;
- 前端直接对比明文密码,数据库不应存储/返回明文密码,应使用哈希验证。
具体修复步骤
解决Pending问题
去掉回调函数的async标记,移除fs.readFileSync前的await(同步方法无需异步等待):app.get('/index', urlencodedParser, function(req, res){ let objJson = { user_name: req.query.user_name || false, password: req.query.password || false }; findUserOne(objJson, function(result){ if(result && result.activate){ const data = fs.readFileSync('./index.html','utf8'); res.set('Content-Type', 'text/html').send(data); }else{ const data = fs.readFileSync('./login.html','utf8'); res.set('Content-Type', 'text/html').send(data); } }); });如果
findUserOne支持Promise,建议改用async/await语法替代回调,代码更清晰:app.get('/index', urlencodedParser, async function(req, res){ try { const result = await findUserOne({ user_name: req.query.user_name || false, password: req.query.password || false }); const htmlPath = result && result.activate ? './index.html' : './login.html'; const data = fs.readFileSync(htmlPath,'utf8'); res.set('Content-Type', 'text/html').send(data); } catch (err) { console.error(err); res.redirect('/login'); } });修复安全问题
- 前端跳转时不再携带密码参数,仅存储必要用户信息:
// 前端登录成功后修改逻辑 if (objJson && objJson.user_name === user_name) { localStorage.setItem('userInfo', JSON.stringify({user_name: objJson.user_name})); window.location.href = '/index'; } - 后端改用Session或JWT验证用户身份,不再依赖URL参数;数据库存储密码哈希(如bcrypt加密),登录时后端对比哈希值,不返回明文密码。
- 前端跳转时不再携带密码参数,仅存储必要用户信息:
内容的提问来源于stack exchange,提问作者Mind full of blanks
相关产品推荐
相关产品推荐

