You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React请求Express接口时req.body.userId为undefined问题排查

问题根因定位

你遇到的req.body.userId始终为undefined,是两处基础用法错误叠加导致的,和你排查过的body-parser配置、CORS规则、React组件传参、MongoDB模型定义都没有关系:

  • 第一处错误:接口路由定义为GET请求,却试图从req.body获取参数。HTTP GET请求规范默认不携带请求体,Express的express.json()中间件只会解析POST/PUT/PATCH这类带请求体的方法的body内容,GET请求下req.body本身就是空对象,自然拿不到任何值。
  • 第二处错误:axios的GET请求传参写法完全错误。axios.get方法只接收两个参数:第一个是请求URL,第二个是请求配置对象。你写的axios.get(url, {userId}, {headers: xxx})属于三参错误写法,{userId}被当成了完整配置对象,后面携带请求头的第三个参数直接被axios忽略,userId根本没有被发送到服务端。

你之前查阅的10多份同类解决方案大多针对「未注册express.json()中间件」的场景,但你已经正确注册了中间件,所以那些方案不生效。

修完主问题后你还会碰到3个隐藏bug,这里一并给出修正方案:

  1. CORS中间件处理OPTIONS预检请求时没有直接返回,会导致请求继续走到后续路由,偶发跨域报错
  2. Post模型中直接使用ObjectId类型但没有从mongoose导入,服务启动时会直接抛出引用错误
  3. 前端mobx中直接从axios返回值取业务字段是错的,axios响应的真实业务数据存放在data字段下,直接取会拿到undefined

逐文件修正方案

1. 服务端路由与控制器修改

两种方案二选一,推荐遵循RESTful规范的方案A:

方案A:保留GET请求,参数走路径/查询参数

修改user.routes路由文件,把userId定义为路径参数:

// 匹配URL格式: /api/user/get/[实际userId值]
router.get('/get/:userId', userController.getUserById)

修改userController中的参数获取逻辑:

async getUserById(req, res) {
    try {
        // 路径参数从req.params对象中取值,如果用查询字符串传参则从req.query取值
        const {userId} = req.params
        console.log(userId) // 此处可正常拿到前端传的userId
        const user = await User.findById(userId)
        if (!user) {
            return res.status(404).json({message: '用户不存在'})
        }
        return res.status(200).json(user)
    } catch (e) {
        console.log(e)
        res.status(500).json({message: '服务端内部错误'})
    }
}

方案B:改为POST请求,从req.body取参数

如果你一定要从请求体传参,直接把路由方法改为POST即可,控制器取参逻辑不用动:

// user.routes文件
router.post('/get', userController.getUserById)

2. 前端mobx请求逻辑修改

对应上面选的方案调整请求写法,同时修正axios返回值取值错误:
如果选方案A(GET+路径参数):

fetchUserData = async(userId) => {
    try {
        // GET请求只传两个参数,userId拼接到路径中,请求头放到第二个配置参数里
        const response = await axios.get(`http://localhost:5000/api/user/get/${userId}`,
        {
            headers:{Authorization: `Bearer ${localStorage.getItem('token')}`},
        })
        // 从响应的data字段取真实业务数据
        const user = response.data
        this.user = user
        this.setUserPage(
            user.login, 
            user._id, 
            user.link, 
            user.friends, 
            user.communities
        )
        console.log(user) 
        console.log(`user id in store ${userId}`)
    } catch (e) {
        console.log(e)
    }
}

如果选方案B(POST+请求体传参):

fetchUserData = async(userId) => {
    try {
        // POST请求第二个参数是请求体,第三个参数才是配置
        const response = await axios.post('http://localhost:5000/api/user/get',
        {userId},
        {
            headers:{Authorization: `Bearer ${localStorage.getItem('token')}`},
        })
        const user = response.data
        // 后续赋值逻辑和上面一致
        this.user = user
        this.setUserPage(
            user.login, 
            user._id, 
            user.link, 
            user.friends, 
            user.communities
        )
    } catch (e) {
        console.log(e)
    }
}

3. CORS中间件修正

修改CORS中间件的OPTIONS请求处理逻辑,直接返回200状态,不要继续走后续路由:

function cors(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*")
    res.header("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE, OPTIONS")
    res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Origin, X-Requested-With, Accept, X-Auth-Token")
    
    if (req.method === "OPTIONS") {
        // 预检请求直接返回,不要调用next()
        return res.sendStatus(200)
    }
    next()
}

4. Post模型修正

导入mongoose的Types对象,正确使用ObjectId类型:

// 开头加Types导入
const {Schema, model, Types} = require('mongoose')
const moment = require('moment')

const Post = new Schema({
    title: {type: String, required: true},
    content: {type: String, required: true},
    // 用Types.ObjectId代替直接写ObjectId
    userId: {type: Types.ObjectId, required: true, ref: 'User'},
    login: {type: String, ref: 'User'},
    likes: {type: Array, default: []},
    dislikes: {type: Array, default: []},
    comments: {type: Array, default: []},
    date: {type: String, default: () => {
        return moment().format('D/MM/YYYY hh:mm')
    }}
})

module.exports = model('Post', Post )

内容的提问来源于stack exchange,提问作者mortvicious

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 06:57:14