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

ExpressJS报Cannot POST /api/v1/users错误的原因排查

Express API POST请求报错"Cannot POST /api/v1/users"排查

我正在开发Express API,应用启动正常,但向http://localhost:3000/api/v1/users发送POST请求时,返回“Cannot POST /api/v1/users”错误。以下是相关代码,求错误原因及解决方法:

User.js(模型)

const mongoose = require('mongoose');

const userSchema = mongoose.Schema({
    name: {
        type: String,
        required: true,
        min: 6,
        max: 255
    },
    email: {
        type: String,
        required: true,
        min: 6,
        max: 1024
    },
    password: {
        type: String,
        required: true,
        minlength: 6
    },
    subscribe: {
        type: Boolean,
        default: false
    },
    date: {
        type: Date,
        default: Date.now
    },
    role: {
        type: String,
        required: false,
        minlength: 4
    },
    address: {
        type: String,
        required: false,
        minlength: 4,
        defaultValue: ""
    },
    nonce: {
        type: String,
        required: false,
        minlength: 4,
        defaultValue: ""
    },
})

module.exports = mongoose.model('User', userSchema);

user.js(控制器)

const Joi = require('@hapi/joi');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const nodemailer = require("nodemailer");

//models
const User = require('../models/user');
const expired_token = require('../models/expired_token');

module.exports = {
    register: async (req, res) => {
        const schemaRegister = Joi.object({
            name: Joi.string().min(3).max(255).required(),
            email: Joi.string().min(4).max(255).required().email(),
            password: Joi.string().min(6).max(1024).required()
        })

        // validate user
        const { error } = schemaRegister.validate(req.body)
        
        if (error) {
            return res.status(400).json({
                data: error,
                message: error.details[0].message,
                status: "error"
            })
        }

        const isEmailExist = await User.findOne({ email: req.body.email });
        if (isEmailExist) {
            return res.status(400).json({
                data: "",
                message: "email already registered",
                status: "error"
            })
        }

        // hash password
        const salt = await bcrypt.genSalt(10);
        const password = await bcrypt.hash(req.body.password, salt);

        const user = new User({
            name: req.body.name,
            email: req.body.email,
            role: "user",
            password: password
        });

        try {
            const savedUser = await user.save();
            console.log(savedUser);
            const token = jwt.sign({
                name: savedUser.name,
                id: savedUser._id,
                email: savedUser.email,
                role: savedUser.role
            }, process.env.TOKEN_SECRET);
            res.status(200).json({
                data: {
                    email:savedUser.email,
                    name: savedUser.name,
                    role: savedUser.role,
                    token: token
                },
                message:"Successful request",
                status: "success"
            });
        } catch (error) {
            res.status(401).json({
                data: error,
                message:"Error creating user",
                status: "error"
            });
        }
    },

    login: async (req, res) => {
        const schemaLogin = Joi.object({
            email: Joi.string().min(6).max(255).required().email(),
            password: Joi.string().min(6).max(1024).required()
        })
        
        const { error } = schemaLogin.validate(req.body);
        if (error) {
            return res.status(400).json({
                data: error,
                message: error.details[0].message,
                status: "error"
            })
        }

        const user = await User.findOne({ email: req.body.email });
        if (!user) {
            return res.status(400).json({
                data: "",
                message: "User not found",
                status: "error"
            })
        }

        const validPassword = await bcrypt.compare(req.body.password, user.password);
        if (!validPassword) {
            return res.status(400).json({
                data: {},
                message: "Invalid password",
                status: "error"
            })
        }

        const token = jwt.sign({
            name: user.name,
            id: user._id,
            email: user.email,
            role: user.role
        }, process.env.TOKEN_SECRET);

        res.status(200).json({
            data: {
                email:user.email,
                name: user.name,
                token: token
            },
            message:"Successful request",
            status: "success"
        });
    },

    list_users: async (req, res) => {
        const users = await User.find({});
        res.status(200).json({
            data: users,
            message:"Successful request",
            status: "success"
        });
    },

    logout: async (req, res) => {
        let user_info = req.decoded;
        let token = req.token;

        const expired_token_exists = await expired_token.findOne({ token: token });
        if (expired_token_exists) {
            return res.status(200).json({
                data: "",
                message: "user already logged out",
                status: "success"
            })
        }

        const data = new expired_token({
            id_user: user_info.id,
            token: token
        });

        try {
            const saved_expired_token = await data.save();
            res.status(200).json({
                data: saved_expired_token,
                message:"Successful request",
                status: "success"
            });
        } catch (error) {
            res.status(401).json({
                data: error,
                message:"Error creating user",
                status: "error"
            });
        }
    },

    get_user_data: async (req, res) => {
        let user_info = req.decoded;
        try {
            const user = await User.find({
                _id:user_info.id
            });
            const user_json=user[0];
            const user_data = {
                id:user_info.id,
                name:user_json.name,
                email:user_json.email,
                subscribe:user_json.subscribe,
                role:user_json.role,
                date:user_json.date
            };
            res.status(200).json({
                data: user_data,
                message:"Successful request",
                status: "success"
            });
        } catch (error) {
            res.status(401).json({
                data: error,
                message:"Error getting user data",
                status: "error"
            });
        }
    }
}

routes/index.js

const { func } = require('@hapi/joi');
const controller = require('../../v1/controllers/users');
const verifyToken = require('../../v1/utils').verifyToken;

module.exports = (router) => {
    router.route('/list_users')
        .get(verifyToken, controller.list_users);

    router.route('/register')
        .post(controller.register);

    router.route('/login')
        .post(controller.login);

    router.route('/logout')
        .post(verifyToken, controller.logout);

    router.route('/get_user_data')
        .get(verifyToken, controller.get_user_data);

    return router;
}

入口文件index.js

let users = require('./v1/routes/users.js');
app.users('/api/v1/users', users(router));

错误原因及解决方法

1. 路由挂载方法错误

Express框架中不存在app.users()这个路由注册方法,正确的路由挂载方式应该使用app.use()。你使用了错误的方法名,导致用户模块的路由完全没有被注册到应用中,所以访问/api/v1/users时会出现找不到路由的错误。

2. 根路径未定义POST处理

你的用户子路由中,仅给/register、/login等子路径配置了POST方法,根路径/api/v1/users本身没有对应的POST路由处理逻辑。如果你的请求是直接发送到根路径而非具体子接口,也会触发该错误。

解决方案

方法一:修正路由挂载代码

将入口文件中的app.users()改为app.use():

let users = require('./v1/routes/users.js');
app.use('/api/v1/users', users(router));

方法二:调整请求目标路径

如果你的需求是调用用户注册接口,应该将POST请求发送到http://localhost:3000/api/v1/users/register,而非根路径/api/v1/users。

可选:给根路径添加POST处理(若有需求)

如果确实需要让根路径支持POST请求,可以在路由文件中添加对应的处理逻辑:

router.route('/')
    .post(controller.yourPostHandler); // 替换为你需要的处理函数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:10:28