使用express.urlencoded后req.body仍为undefined的问题排查
Express项目中req.body始终为undefined的排查与解决
问题背景
已在Express项目中配置app.use(express.urlencoded({ extended: false}))处理表单数据,且HTML表单所有input元素的name属性与代码匹配,但req.body始终返回undefined。相关代码如下:
原JavaScript代码
//Constantes const express = require('express'); const port = process.env.PORT || 3000; const exphbs = require("express-handlebars"); const passport = require("passport"); const session = require("express-session"); //--------------- const bcrypt = require("bcrypt"); const passport_local = require("passport-local"); const LocalStrategy = passport_local.Strategy; const connection = require("./database"); //----------------- //Config const app = express(); app.use(express.urlencoded({ extended: false})); app.engine(".hbs", exphbs.engine()); app.set('view engine', ".hbs"); //-------------------- passport.use("local.signup", new LocalStrategy({ usernameField: "email", passwordField: "password", passReqToCallback: true }, async (username, password, req, done) => { console.log(req.body); const salt = await bcrypt.genSalt(10); const hash = await bcrypt.hash(password, salt); const user = { email: username, password: hash, nombre: req.body.nombre, apellido: req.body.apellido}; const result = await connection.query("INSERT INTO usuarios SET ?", user); user.id = result.insertId; return done(null, user.id); })); passport.serializeUser((user, done) => { return done(null, user.id); }); passport.deserializeUser( async (id, done) => { const rows = await connection.query(`SELECT id, email FROM usuarios WHERE id = ${id}`) return done(null, rows[0]); }); //----------------------------------- app.use(passport.initialize()); app.use(session({ secret: "secreto", resave: false, saveUninitialized: true, })); app.use(passport.session()); app.listen(port, () => { console.log("listening on port " + port); }); app.use(require("./routes/index.js")); app.use(require("./routes/register.js"));
原HTML表单代码
<!-- Formulario de registro --> <section class="container-fluid"> <div class="row justify-content-center align-content-center m-5"> <h1 class="text-center mt-5">Registro Administrador</h1> <div class="col-xl-4 col-lg-8 col-md-8 col-xs-12"> <form action="/register" method="post" class=" border border-2 border-dark p-4 rounded"> <div class="form-group p-2"> <label for="email">E-Mail <span class="text-danger">*</span></label> <input id="email" class="form-control" type="email" placeholder="marcos@example.com" required name="email" value="{{ email }}"> </div> <div class="form-group p-2"> <label for="password">Contraseña <span class="text-danger">*</span></label> <input id="password" class="form-control" type="password" placeholder="*********" required name="password"> </div> <div class="form-group p-2"> <label for="nombre">nombre <span class="text-danger">*</span></label> <input id="nombre" class="form-control" type="text" placeholder="nombre" required name="nombre"> </div> <div class="form-group p-2"> <label for="apellido">apellido <span class="text-danger">*</span></label> <input id="apellido" class="form-control" type="text" placeholder="apellido" required name="apellido"> </div> <div class="d-grid p-2"> <button type="submit" class="btn btn-light btn-outline-dark outline">Registrarse</button> </div> <div class="d-grid p-2 "> <a href="/login" class="btn btn-light btn-outline-dark outline">Ya tenes cuenta? Logeate!</a> </div> </form> </div> </div> </section>
排查出的问题点
Passport LocalStrategy回调参数顺序错误
当设置passReqToCallback: true时,回调函数的第一个参数必须是req(请求对象),原代码中将username放在首位,导致req参数被错误赋值为done函数,无法获取表单数据。Session与Passport中间件顺序颠倒
express-session中间件必须在passport.initialize()和passport.session()之前注册,否则Passport无法正确利用session管理认证状态,可能导致请求处理异常。app.listen()位置不当app.listen()应放在所有中间件、路由注册完成之后,确保所有配置生效。原代码中app.listen()提前执行,虽不影响语法,但不符合Express最佳实践,可能引发潜在加载问题。
修复后的代码
调整Passport策略回调参数顺序
passport.use("local.signup", new LocalStrategy({ usernameField: "email", passwordField: "password", passReqToCallback: true }, async (req, username, password, done) => { // 将req调整为第一个参数 console.log(req.body); // 现在可正常获取表单数据 const salt = await bcrypt.genSalt(10); const hash = await bcrypt.hash(password, salt); const user = { email: username, password: hash, nombre: req.body.nombre, apellido: req.body.apellido}; const result = await connection.query("INSERT INTO usuarios SET ?", user); user.id = result.insertId; return done(null, user.id); }));
调整中间件与服务器启动顺序
// 先注册session中间件 app.use(session({ secret: "secreto", resave: false, saveUninitialized: true, })); // 再初始化Passport app.use(passport.initialize()); app.use(passport.session()); // 注册路由 app.use(require("./routes/index.js")); app.use(require("./routes/register.js")); // 最后启动服务器 app.listen(port, () => { console.log("listening on port " + port); });
验证方法
- 重启Express服务器,提交注册表单,查看控制台输出的
req.body,应能显示完整的表单字段数据。 - 检查数据库,确认用户信息被正确插入,说明
req.body.nombre、req.body.apellido等字段已正常读取。
内容的提问来源于stack exchange,提问作者user19729277
相关产品推荐
相关产品推荐

