followUsers函数未将ID加入followers/followings数组且无请求响应的修复
用户关注功能异常排查与修复
问题概述
基于Node.js + MongoDB的项目中,用户关注功能失效:完成JWT认证拿到token后调用followUsers接口,既没有收到响应,数据库里的followers和followings数组也没更新。
原代码问题排查
1. verifyToken.js 语法与逻辑错误
- if语句未闭合大括号,导致代码结构混乱
next()被错误嵌套在else分支内,正常认证后无法触发后续中间件- 异常捕获后仅打印错误,未调用
next(error)或返回错误响应,导致请求挂起
2. User.js Schema语法错误
timestamps: true被错误放在了schema字段对象内部,应该作为第二个参数传入mongoose.Schemafullname设置unique: true不合理,会导致重名用户无法注册
3. userRoutes.js 路由路径错误
- 好友列表路由缺少前置斜杠,应为
/friends/:userId,否则无法匹配请求
4. controllers/User.js 语法与逻辑错误
followUsers函数中if语句未闭合大括号,代码结构错误- 逻辑判断错误:else分支提示"已关注自己",实际应该是"已关注该用户"
- 未处理用户不存在的情况(比如
findById返回null) unfollowUsers函数中字段名错误:使用了follower/following,但Schema定义的是followers/followings- 存在语法缺失(比如res.status后缺少分号,if/else闭合问题)
修复后的完整代码
1. verifyToken.js
import jwt from 'jsonwebtoken'; export const verifyToken = (req, res, next) => { try { const token = req.headers.authorization?.split(" ")[1]; const isCustomAuth = token?.length < 500; let decodedData; if (token && isCustomAuth) { decodedData = jwt.verify(token, process.env.JWT_KEY); req.user = decodedData?.id; } else { decodedData = jwt.decode(token); req.user = decodedData?.sub; } // 认证成功后触发后续中间件 next(); } catch (error) { console.log(error); // 传递错误到全局错误处理中间件 next(error); } };
2. User.js
import mongoose from "mongoose"; export const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true, max: 50, }, username: { type: String, required: true, unique: true, max: 20, }, fullname: { type: String, required: true, max: 50, }, password: { type: String, required: true, min: 6, }, followings: { type: Array, default: [], }, followers: { type: Array, default: [], }, profilePicture: { type: String, default: "", }, coverPicture: { type: String, default: "", }, location: { type: String, max: 30, }, website: { type: String, default: "", max: 100, }, dateOfBirth: { type: String, required: true, match: /^\d{2}[-]\d{2}[-]\d{4}$/, }, }, { timestamps: true }); export default mongoose.model('Users', userSchema);
3. userRoutes.js
import express from 'express'; import { verifyToken } from '../middleware/verifyToken.js'; import { update, deleteUser, getUser, friendsList, followUsers, unfollowUsers } from '../controllers/User.js'; const router = express.Router(); // 更新用户 router.put('/:id', verifyToken, update); // 删除用户 router.delete('/:id', verifyToken, deleteUser); // 获取用户 router.get('/find/:id', getUser); // 好友列表 router.get('/friends/:userId', friendsList); // 关注用户 router.put('/follow/:id', verifyToken, followUsers); // 取消关注用户 router.put('/unfollow/:id', verifyToken, unfollowUsers); export default router;
4. controllers/User.js
import User from '../models/User.js'; import { createError } from '../utils/error.js'; export const followUsers = async (req, res, next) => { if (req.params.id !== req.user?.id) { try { const targetUser = await User.findById(req.params.id); const currentUser = await User.findById(req.user?.id); if (!targetUser || !currentUser) { return next(createError(404, "用户不存在")); } if (!targetUser.followers.includes(req.user?.id)) { await targetUser.updateOne({ $push: { followers: req.user?.id } }); await currentUser.updateOne({ $push: { followings: req.params.id } }); res.status(200).json("已成功关注该用户"); } else { return next(createError(403, "你已经关注了该用户")); } } catch (error) { console.error(error); next(error); } } else { return next(createError(403, "无法关注自己的账号")); } }; export const unfollowUsers = async (req, res, next) => { if (req.params?.id !== req.user?.id) { try { const targetUser = await User.findById(req.params.id); const currentUser = await User.findById(req.user.id); if (!targetUser || !currentUser) { return next(createError(404, "用户不存在")); } if (targetUser.followers.includes(req.user?.id)) { await targetUser.updateOne({ $pull: { followers: req.user?.id } }); await currentUser.updateOne({ $pull: { followings: req.params.id } }); res.status(200).json("已成功取消关注"); } else { return next(createError(403, "你还未关注该用户")); } } catch (error) { next(error); } } else { return next(createError(403, "无法取消关注自己的账号")); } };
额外优化建议
- 使用事务确保关注/取消关注操作的原子性:如果其中一个更新失败,另一个也应该回滚,避免数据不一致
- 将数组字段改为关联ObjectId数组,提升数据规范性:
followings: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Users', default: [] }], followers: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Users', default: [] }]
- 添加请求参数校验(比如使用
joi或express-validator),避免传入无效的用户ID
内容的提问来源于stack exchange,提问作者Mehmet Ali Koyuncuoglu
相关产品推荐
相关产品推荐

