使用NextJS、Mongoose与Bcrypt搭建登录API时遇请求未响应错误
问题原因与解决方案
你遇到的API resolved without sending a response错误,本质是两个逻辑问题导致Next.js无法正确识别请求已完成:
1. 用户不存在分支未终止函数执行
当!user条件成立时,你返回了错误响应,但没有终止后续代码执行。函数会继续走到user.comparePassword这一行,此时user是undefined,会触发异常进入catch块,但这个异步流程会让Next.js误以为响应未正确发送。
2. 回调式异步导致函数提前结束
comparePassword使用回调函数处理密码比对,而你的handler是async函数——执行到user.comparePassword(...)后,handler会直接走到函数末尾,此时密码比对的回调还没执行,Next.js就判定请求已处理但未发送响应,从而抛出警告。
修复步骤
第一步:改造comparePassword为Promise风格
将回调式方法改为支持await的Promise版本,适配async函数的异步流程:
UserSchema.methods.comparePassword = async function(candidatePassword: string) { // 直接利用bcrypt.compare的Promise特性,无需手动封装回调 return bcrypt.compare(candidatePassword, this.password); };
第二步:修正登录API的逻辑分支
添加return终止函数流程,用await等待密码比对完成:
import dbConnect from "../../lib/dbConnect"; import User from "../../models/User" import type { NextApiRequest, NextApiResponse } from 'next' export default async function handler( req: NextApiRequest, res: NextApiResponse ) { await dbConnect() const {method} = req if (method === "POST") { try { const user = await User.findOne({email: req.body.email}); if (!user) { // 添加return,终止函数后续执行 return res.status(400).json({error: "email not found"}) } // 用await等待密码比对结果 const isMatch = await user.comparePassword(req.body.password); if (isMatch) { return res.status(200).json({success: "password matches"}) } else { return res.status(400).json({error: "password does not match"}) } } catch (error) { console.error(error); // 打印错误便于调试 return res.status(500).json({error: "server error"}) } } else { // 处理非POST请求,返回405方法不允许 return res.status(405).json({error: "Method not allowed"}) } }
额外优化点
- 把catch块的400状态码改为500,更符合服务器错误的语义
- 新增非POST请求的处理分支,避免请求方法错误时无响应
内容的提问来源于stack exchange,提问作者qwertysoldier
相关产品推荐
相关产品推荐

