Node.js Express 注册表单提交触发页面无限加载问题
问题根因
- 核心触发点:POST路由注册时机错误。你将
/create-new-acc的POST处理逻辑写在了http.listen()的回调函数内部,该回调仅在服务完成端口监听启动后异步执行1次,服务启动接收请求的时间早于路由注册时间,首批到达的请求无法匹配到处理逻辑;同时这种写法本身违背Express中间件/路由的注册规则,会导致路由匹配异常。 - 直接导致挂起的原因:请求解析中间件重复且冲突。你先后注册了3次urlencoded请求解析(2次来自独立的body-parser包、1次为Express内置能力)、1次JSON解析,还额外全局挂载了
express-formidable中间件。普通application/x-www-form-urlencoded格式的表单提交不需要formidable处理,多个解析中间件同时运行会争抢消费请求流,前一个中间件消费完流数据后,后续中间件会一直等待流数据传输完成,导致请求全程挂起,不会返回任何响应,浏览器就会一直处于等待状态,表现为无限加载。 - 业务逻辑隐患:表单内所有输入控件都未配置
name属性,就算请求链路正常,后端也无法通过req.body获取到用户提交的表单字段值。
修复方案
- 调整路由注册位置:所有路由、中间件必须在调用
http.listen()启动服务前完成注册,不要在listen的回调函数内编写路由、挂载中间件。 - 清理冗余冲突中间件:高版本Express已经内置了body-parser的解析能力,不需要额外引入body-parser包;普通表单提交场景不需要使用formidable,删除重复、无用的解析中间件,只保留必要的解析逻辑即可。
- 补全表单属性:给所有需要提交到后端的input控件添加对应
name属性,属性值和后端要读取的字段名保持一致。
修复后参考代码
后端服务代码
const express = require('express'); const mysql = require('mysql'); const app = express(); const http = require('http').createServer(app); // 仅保留必要的中间件,删除重复冗余项 app.use(express.urlencoded({extended: true})); app.use(express.json()); app.use(express.static(__dirname + '/views')); app.use("/public", express.static(__dirname + '/public')); app.set('view engine', 'ejs'); const pool = mysql.createPool({ connectionLimit : 10, host: 'localhost', user: 'root', password: '', database: 'alazanidb' }); // 服务启动前注册路由 app.post('/create-new-acc', (req,res) =>{ // 后续可在此处通过req.body读取表单字段、执行数据库入库逻辑 res.redirect('/entry/signin'); }) // 所有逻辑注册完成后再启动监听 http.listen(3000, function(){ console.log('服务运行在3000端口'); })
表单部分代码
<div class="registration-popup" id="regpopup"> <form action="/create-new-acc" method="POST" > <div class="content"> <h1 id="h1">Create new account</h1> <div class="input"> <input type="text" placeholder="First Name" class="inp" id="name" name="firstName"/> </div> <div class="input"> <input type="text" placeholder="Second Name" class="inp" id="secname" name="secondName"/> </div> <div class="input"> <input type="text" placeholder="Username" class="inp" id="username" name="username"/> </div> <div class="input"> <input type="tel" placeholder="Phone Number" class="inp" id="phone" name="phone"/> </div> <div class="input"> <input type="text" placeholder="Address" class="inp" id="addres" name="address"/> </div> <div class="input"> <input type="password" placeholder="Password" class="inp" id="pass" name="password"/> </div> <div class="input"> <input type="password" placeholder="Repeat password" class="inp" id="repass" name="repeatPassword"/> </div> <input type="submit" id="register" value="register" > <input type="button" id="reset" value="Reset" onclick="resett()" > </div> </form> </div>
内容的提问来源于stack exchange,提问作者striker vinchester
相关产品推荐
相关产品推荐

