使用JsonWebToken时遇TypeError,无法获取用户数据求助
问题:JWT登录时获取用户数据失败,出现
TypeError: Cannot read properties of null (reading '_id') 我在学习JsonWebToken基础时,用简洁代码实践。MongoDB里建了小数据库,文档包含_id、name、age、username字段。用Node.js写代码时,一直报错:TypeError: Cannot read properties of null (reading '_id')。如果移除payload里的userId,能拿到带令牌的响应,但data属性是null(即"data": {"doc": null})。我用Postman发POST请求,raw JSON格式,请求体输入{"username": "john25"}/{"username": "george15"}/{"username": "jim35"},地址是localhost:5000/login。相关代码如下:
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){ const {username} = req.body; User.findOne({ username }) .then(function(doc){ const userId = doc._id; const token = jwt.sign({ userId }, 'abc123', {expiresIn: 250}); return res.status(200).json({status: 'success', token, data: {doc}}); }); } app.post('/login', login); mongoose.connect('mongodb+srv://username:password@cluster0.epwfttj.mongodb.net/? retryWrites=true&w=majority') .then(() => app.listen(5000)) .catch(err => console.log(err));
问题原因及解决办法
核心问题:查询不到匹配的用户文档
报错doc._id是因为User.findOne({username})返回了null,说明数据库里没有和请求体中username匹配的文档,可能的原因:
- 集合名称不匹配:Mongoose默认会把模型名
User转为小写复数形式的集合名(即users),如果你的数据库集合不是这个名字,需要在定义模型时指定集合名:const User = mongoose.model('User', userSchema, '你的集合名'); - 用户名不一致:MongoDB查询默认区分大小写,确认请求里的
username和数据库里的拼写、大小写完全一致 - 数据库连接错误:当前连接字符串没有指定具体数据库,默认会连接
test库,需要修改连接字符串为mongodb+srv://username:password@cluster0.epwfttj.mongodb.net/你的数据库名?retryWrites=true&w=majority,确保连接到存放用户数据的库
代码层面完善
必须处理查询结果为null的情况,避免报错,同时增加异常捕获:
function login(req, res){ const {username} = req.body; User.findOne({username}) .then(function(doc){ if (!doc) { return res.status(404).json({status: 'error', message: '用户不存在'}); } const userId = doc._id; const token = jwt.sign({ userId }, 'abc123', {expiresIn: 250}); return res.status(200).json({status: 'success', token, data: {doc}}); }) .catch(function(err) { return res.status(500).json({status: 'error', message: '服务器内部错误', error: err.message}); }); }
额外建议
- 不要把数据库密码、JWT密钥硬编码在代码里,用环境变量存储(比如
process.env.MONGODB_URI、process.env.JWT_SECRET) expiresIn: 250单位是秒,可根据实际需求调整过期时长
内容的提问来源于stack exchange,提问作者Miriyan Asenov
相关产品推荐
相关产品推荐

