Node+Express中Promise的then里res.redirect非函数问题求助
问题分析与修复方案
你遇到的TypeError: res.redirect is not a function错误,核心原因是变量命名冲突,把Express的响应对象给覆盖了!
为什么会出现这个错误?
看你的路由代码里这段:
signup.signup(user) .then((res)=>{ req.session.msgs = [{msg: res}]; res.redirect('/events'); // 错误指向这里 }, ...)
你在then的成功回调里把参数命名为res,但这个名字和外层Express路由的res(也就是用来处理HTTP响应的核心对象)完全重名了!这就导致回调函数内部的res,指向的是Promise成功返回的值(也就是你在signup函数里resolve的user.email),而不是原来的Express响应对象——一个字符串当然没有redirect方法啦。
修复步骤
1. 解决变量命名冲突
把then回调里的参数名改成别的,比如result或者userEmail,避免和外层的res冲突:
router.post('/save', (req, res)=>{ req.checkBody('email', 'put email').notEmpty().trim(); let errors = req.validationErrors(); if (errors) { req.session.msgs = errors; res.redirect('/signup'); } else { var user = {email:req.body.email}; signup.signup(user) .then((result)=>{ // 这里把参数名改成result req.session.msgs = [{msg: result}]; res.redirect('/events'); // 现在res就是原来的Express响应对象了 }, (rej)=>{ req.session.msgs = [{msg: 'err'}]; // 建议先设置session再跳转,避免丢失 res.redirect('/signup'); }) .catch((err)=>{ req.session.msgs = [{msg: 'err'}]; res.redirect('/signup'); }); } });
2. 修复signup函数的异步逻辑(潜在bug)
你的signup函数还有个隐藏问题:client.query是异步操作,但你现在直接在调用query后立刻执行done()和res(user.email),这会导致数据库插入操作还没完成,连接就被释放了,甚至可能出现数据插入失败但Promise已经resolve的情况。正确的写法是把连接释放和Promise的resolve/reject放在query的回调里:
const signup = (user) => { return new Promise((resolve, reject)=>{ pool.connect( (err, client, done) => { if (err) { done(); // 连接失败也要释放连接,避免连接泄漏 return reject(err); } // 把query的回调加上,确保数据库操作完成后再处理 client.query('insert into "user" (email) values($1)',[user.email], (queryErr) => { done(); // 无论查询成功失败,都要释放连接 if (queryErr) { return reject(queryErr); } resolve(user.email); }); }); }); }; exports.signup = signup;
另外注意:user是PostgreSQL的关键字,你的表名如果是user,需要用双引号包裹("user"),或者改成users之类的非关键字名称,否则会触发SQL语法错误。
内容的提问来源于stack exchange,提问作者slevin
相关产品推荐
相关产品推荐

