Node.js+MongoDB社交网络Follow/Unfollow接口Postman请求异常排查
问题分析与修复方案
问题代码
module.exports.follow = async (req, res) => { if ( !ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToFollow) ) return res.status(400).send("ID unknown : " + req.params.id); try { // add to the follower list await UserModel.findOneAndUpdate( req.params.id, { $addToSet: { following: req.body.idToFollow } }, { new: true, upsert: true } .then((data) => res.send(data)) .catch((err) => res.status(500).send({ message: err }))), // add to following list await UserModel.findOneAndUpdate( req.body.idToFollow, { $addToSet: { followers: req.params.id } }, { new: true, upsert: true } .then((data) => res.send(data)) .catch((err) => res.status(500).send({ message: err }))) } catch (err) { return res.status(500).json({ message: err }); } }; module.exports.unfollow = async (req, res) => { if ( !ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToUnfollow) ) return res.status(400).send("ID unknown : " + req.params.id); try { await userModel.findOneAndUpdate( req.params.id, { $pull: { following: req.body.idToUnfollow } }, { new: true, upsert: true } .then((data) => res.send(data)) .catch((err) => res.status(500).send({ message: err }))), // Retirer de la liste des followers await userModel.findOneAndUpdate( req.body.idToUnfollow, { $pull: { followers: req.params.id } }, { new: true, upsert: true } .then((data) => res.send(data)) .catch((err) => res.status(500).send({ message: err }))) } catch (err) { return res.status(500).json({ message: err }); } }
核心问题
- 混用async/await与.then/.catch:await已会等待Promise完成,再链式调用.then会导致结构错误,内层.catch会拦截部分错误但外层try/catch无法处理;同时多次调用
res.send()会触发"Cannot set headers after they are sent to the client"错误,直接进入外层catch。 - 模型名称大小写不一致:follow方法用
UserModel,unfollow方法用userModel,Node.js变量大小写敏感,会导致找不到模型报错。 - 重复发送响应:一次HTTP请求只能返回一次响应,两次
res.send(data)违反协议,必然触发错误。
修复后的代码
const ObjectID = require("mongodb").ObjectID; // 确保模型路径正确,统一使用大写开头的变量名 const UserModel = require("../models/User"); module.exports.follow = async (req, res) => { // 验证两个ID有效性 if ( !ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToFollow) ) { return res.status(400).send(`ID unknown: ${req.params.id}`); } try { // 并行执行两个更新操作,提升性能 const [followerUpdate, followingUpdate] = await Promise.all([ // 更新关注者的following列表 UserModel.findOneAndUpdate( req.params.id, { $addToSet: { following: req.body.idToFollow } }, { new: true, upsert: true } ), // 更新被关注者的followers列表 UserModel.findOneAndUpdate( req.body.idToFollow, { $addToSet: { followers: req.params.id } }, { new: true, upsert: true } ) ]); // 统一返回更新结果 return res.status(200).json({ follower: followerUpdate, following: followingUpdate }); } catch (err) { return res.status(500).json({ message: err.message }); } }; module.exports.unfollow = async (req, res) => { if ( !ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToUnfollow) ) { return res.status(400).send(`ID unknown: ${req.params.id}`); } try { const [followerUpdate, followingUpdate] = await Promise.all([ UserModel.findOneAndUpdate( req.params.id, { $pull: { following: req.body.idToUnfollow } }, { new: true, upsert: true } ), UserModel.findOneAndUpdate( req.body.idToUnfollow, { $pull: { followers: req.params.id } }, { new: true, upsert: true } ) ]); return res.status(200).json({ follower: followerUpdate, following: followingUpdate }); } catch (err) { return res.status(500).json({ message: err.message }); } };
额外注意事项
- 确保
UserModel的引入路径正确,且模型中已定义following和followers数组字段。 - 使用
Promise.all()并行执行更新,避免串行等待浪费时间。 - 测试时确认Postman请求参数正确:
params.id为当前用户ID,body.idToFollow/body.idToUnfollow为目标用户ID,请求方法为PATCH。
内容的提问来源于stack exchange,提问作者Gabriel Bidias
相关产品推荐
相关产品推荐

