Node.js中JWT登录报TypeError: Cannot read properties of null (reading '_id')求助
问题
学习JsonWebToken基础时,在Node.js中编写登录接口遇到两个问题:
- 直接访问
doc._id时报错:TypeError: Cannot read properties of null (reading '_id') - 移除
doc._id后能生成令牌,但返回的data.user为null
已在MongoDB中创建包含_id、name、age、username字段的用户集合,相关代码如下:
const express = require('express'); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const app = express(); app.use(bodyParser.json()); const userSchema = new mongoose.Schema({ name: { type: String, required: true }, age: { type: Number, required: true }, username: { type: String, required: true }, }); const User = mongoose.model('User', userSchema); function login(req, res){ User.findOne({ username }) .then(function(doc){ const token = jwt.sign({ doc._id }, 'abc123', {expiresIn: 250}); return res.status(200).json({status: 'success', token, data: {doc}}); }); } app.post('/login', login);
错误原因分析
- 未获取请求体中的username参数:
User.findOne({ username })里的username未定义,需从req.body中获取前端传入的用户名,否则查询条件无效,返回的doc为null,访问doc._id必然报错。 - 缺少查询结果校验逻辑:没有判断是否找到用户,直接对
doc进行操作,当用户不存在时就会触发null的属性访问错误。 - 响应数据键名不匹配:代码返回
data: {doc},但你期望的是data.user,键名不一致导致前端拿到的user为null。
修复后的代码
const express = require('express'); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const app = express(); app.use(bodyParser.json()); // 补充数据库连接逻辑 mongoose.connect('mongodb://localhost:27017/你的数据库名') .then(() => console.log('数据库连接成功')) .catch(err => console.error('数据库连接失败:', err)); const userSchema = new mongoose.Schema({ name: { type: String, required: true }, age: { type: Number, required: true }, username: { type: String, required: true }, }); const User = mongoose.model('User', userSchema); function login(req, res){ // 从请求体获取用户名 const { username } = req.body; if (!username) { return res.status(400).json({ status: 'fail', message: '请传入用户名' }); } User.findOne({ username }) .then(function(doc){ // 判断是否找到用户 if (!doc) { return res.status(404).json({ status: 'fail', message: '用户不存在' }); } // 生成JWT,将_id命名为更清晰的userId const token = jwt.sign({ userId: doc._id }, 'abc123', { expiresIn: '250s' }); // 返回符合预期的data.user结构 return res.status(200).json({ status: 'success', token, data: { user: doc } }); }) .catch(function(err) { // 处理数据库查询错误 return res.status(500).json({ status: 'error', message: '服务器内部错误', error: err.message }); }); } app.post('/login', login); // 启动服务 app.listen(3000, () => console.log('服务运行在http://localhost:3000'));
补充说明
- 必须补充MongoDB连接代码,否则无法正常查询数据库;
expiresIn参数传入数字时单位为秒,也可通过字符串指定单位(如'1h'表示1小时);- 生产环境不要将JWT密钥('abc123')硬编码,建议用环境变量存储;
- 实际登录逻辑通常还需校验密码,此处为最简实践暂保留仅查询用户名的逻辑。
内容的提问来源于stack exchange,提问作者Miriyan Asenov
相关产品推荐
相关产品推荐

