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

Node.js+EJS项目中/admin/blogs/edit/:id路由无法获取请求体

问题描述

我使用Node.js、EJS模板、MongoDB和Express开发Web应用,已创建包含用户及其他数据库操作的多组路由。/register路由的POST请求可正常获取请求体数据,但/admin/blogs/edit/:id路由无法获取任何请求体内容,浏览器与控制台均无报错信息,仅返回空对象。相关代码及控制台输出如下:

app.js代码

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}

const express = require('express');
const mongoose = require('mongoose');
const ejsLayouts = require('express-ejs-layouts');
const cors = require('cors');
const passport = require('passport');
const flash = require('express-flash');
const session = require('express-session');
const methodOverride = require('method-override');
const webRoutes = require('./routes/webRoutes');
const userRoutes = require('./routes/userRoutes');
const initializePassport = require('./passport-config');

const app = express();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));

app.set('view engine', 'ejs');
app.use(ejsLayouts);

app.use(function(req, res, next) {
    res.locals.currentPage = req.path;
    next();
});

app.use("/", webRoutes);
app.use("/admin", userRoutes);

mongoose.connect('mongodb://127.0.0.1:27017/myDB');

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

userRoutes.js代码

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}

let express = require('express');
const app = express();
const router = express.Router();
const bcrypt = require('bcrypt');
const passport = require('passport');
const flash = require('express-flash');
const session = require('express-session');
const methodOverride = require('method-override');
const fs = require('fs');
const path = require('path');
const { Blog, Contact, JobOpening, User } = require('../models/dbModels');

const initializePassport = require('../passport-config')
initializePassport(
    passport, 
    email => users.find(user => user.email === email),
    id => users.find(user => user.id === id)
)

router.use(flash())
router.use(session({
    secret: process.env.SECRET_KEY,
    resave: false,
    saveUninitialized: false
}))
router.use(passport.initialize())
router.use(passport.session())
router.use(methodOverride('_method'))

// Function to get JavaScript filenames
function getAdminJSFiles() {
    const adminJsDir = path.join(__dirname, '..', 'public', 'javascript', 'admin');
    const files = fs.readdirSync(adminJsDir);
    const jsFiles = files.filter(file => file.endsWith('.js'));
    return jsFiles;
}

// Function to get JavaScript filenames
function getAdminCSSFiles() {
    const adminCSSDir = path.join(__dirname, '..', 'public', 'styles', 'admin');
    const files = fs.readdirSync(adminCSSDir);
    const cssFiles = files.filter(file => file.endsWith('.css'));
    return cssFiles;
}

const current_user = true;

// Middleware to set layout for all admin routes
router.use((req, res, next) => {
    if (req.originalUrl.startsWith('/admin/login')) {
        // Exclude layout for login routes
        res.locals.layout = 'layout_login';
        return next();
    }
    res.locals.layout = 'layout_admin'; // Specify the admin layout
    res.locals.jsFiles = getAdminJSFiles(); // Pass the jsFiles variable
    res.locals.cssFiles = getAdminCSSFiles(); // Pass the jsFiles variable
    res.locals.user = { name: "dummyUser", email: 'dummyUser@gmail'}
    next();
});

router.use((req, res, next) => {
    if (req.isAuthenticated()) {
        if (req.originalUrl === '/admin/login') {
            return res.redirect('/admin');
        }
        return next();
    }
    if (req.originalUrl === '/admin/login') {
        return next();
    }
    res.redirect('/admin/login');
});

router.get('/', (req, res) => {
    res.render('./admin/admin_home', { current_user: req.body.email, email: req.body.name, params: req.params });
});

router.get('/register', (req, res) => {
    res.render('./admin/admin_register');
});

router.post('/register', async (req, res) => {
    try {
        const hashedPassword = await bcrypt.hash(req.body.password, 10);
        const newUser = new User({
            email: req.body.email,
            password: hashedPassword,
            role: req.body.role
        });
        await newUser.save();
        res.redirect('/admin/login');
    } catch (error) {
        console.error(error);
        res.redirect('/admin/register');
    }
});

router.get('/login', (req, res) => {
    res.render('./admin/admin_login');
});

router.post('/login', passport.authenticate('local', {
    successRedirect: '/admin',
    failureRedirect: '/admin/login',
    failureFlash: true
}));

router.get('/logout', (req, res, next) => {
    req.logout((err) => {
        if (err) { return next(err); }
        res.redirect('/admin');
    });
});

router.get('/blogs', async (req, res) => {
    try {
      const blogs = await Blog.find();
      res.render('./admin/blogs/blog_home', { blogs });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
  });

router.get('/blogs/add', async (req, res) => {
    try {
      res.render('./admin/blogs/blog_add', { action: `/admin/blog/add`, blog: {} });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
}); 

router.get('/blogs/edit/:id', async (req, res) => {
    try {
        const blog = await Blog.findById(req.params.id);
      res.render('./admin/blogs/blog_add', { action: `/admin/blogs/edit/${blog._id}`, blog });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
});

router.post('/blogs/edit/:id', async (req, res) => {
    try {
        const userID = req.params.id;
        console.log(userID)
        const { title } = req.body;
        console.log('Request Body:', req.body); // Log request body
        console.log('Update Query:', { title }); // Log update query
        res.redirect('/admin/blogs');

    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
});

module.exports = router;

blog_add.ejs代码

<div class="content-wrapper">
    <section class="content-header">
        <h1>New</h1>
        <div class="breadcrumb">
            <a class="btn btn-sm btn-info" href="/admin/blogs">Back</a>
        </div>
    </section>
    <section class="content">
        <%- include ('../../partials/admin_form')%>
    </section>
</div>

admin_form.ejs代码

<% // include partials/layouts/include_ckeditor.ejs %>
<div class="box box-default">
    <div class="box-header with-border">
        <h3 class="box-title">Form</h3>
        <div class="box-tools pull-right">
            <button class="btn btn-box-tool" data-widget="collapse">
                <i class="fa fa-minus"></i>
            </button>
        </div>
    </div>
    <h1><%= blog ? 'Edit blog' : 'Add blog' %></h1>
    <form action="<%= action %>" method="post" enctype="multipart/form-data">
        <div class="box-body">
            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label>Title</label>
                        <input type="text" name="title" class="form-control" placeholder="Enter Title" value="<%= blog.title || '' %>">
                    </div>
                    <div class="form-group">
                        <label>SEO Name</label>
                        <input type="text" name="seo_name" class="form-control" placeholder="Enter SEO Name" value="">
                    </div>
                    <div class="form-group">
                        <label>Blog Type</label>
                        <select name="blog_type" class="form-control">
                            <option value="BLOG">BLOG</option>
                            <option value="NEWS">NEWS</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Author Name</label>
                        <input type="text" name="author_name" class="form-control" placeholder="Enter Author Name" value="">
                    </div>
                    <div class="form-group">
                        <label>Image</label>
                        <input type="file" name="image" class="form-control">
                        <p style="color:red;">(530px X 429 px)</p>
                    </div>
                    <div class="form-group">
                        <label>Banner Image</label>
                        <input type="file" name="banner_image" class="form-control">
                        <p style="color:red;">(1015px X 452 px)</p>
                    </div>
                    <div class="form-group">
                        <label>Publish Date</label>
                        <input type="text" name="publish_date" class="form-control" placeholder="Enter Publish Date" id="adrt-datepicker" autocomplete="off" value="">
                    </div>
                    <div class="form-group">
                        <label>Status</label>
                        <input type="checkbox" name="status">
                    </div>
                    <div class="form-group">
                        <label>Trending Blog</label>
                        <input type="checkbox" name="trending">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label>Long Description</label>
                        <textarea name="long_description" class="form-control"></textarea>
                    </div>
                </div>
            </div>
        </div>
        <div class="box-footer">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </form>
</div>

<script>
    $(document).ready(function(){
        $("#adrt-datepicker").datepicker({
            dateFormat: 'dd/mm/yy',
            maxDate: 0
        });
    });
</script>

控制台输出

id: 65eb8dce672a051114e1a090
Request Body: {}
Update Query: { title: undefined }

问题原因及解决方法

表单设置了enctype="multipart/form-data"(用于文件上传),但Express默认的express.urlencoded中间件无法解析这种格式的请求体,这就是req.body为空的核心原因。而/register路由的表单没有文件上传字段,所以能被正常解析。

解决步骤

  1. 安装multer中间件:multer是Express生态中专门处理multipart/form-data格式请求的工具:
npm install multer
  1. 在userRoutes.js中配置multer:
const multer = require('multer');
// 用内存存储文件,也可以配置磁盘存储路径,按需选择
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
  1. 修改编辑博客的POST路由:添加multer中间件来解析请求体:
router.post('/blogs/edit/:id', upload.any(), async (req, res) => {
    try {
        const blogID = req.params.id;
        console.log(blogID)
        const { title } = req.body;
        console.log('Request Body:', req.body);
        console.log('Update Query:', { title });
        // 执行数据库更新操作
        await Blog.findByIdAndUpdate(blogID, req.body);
        res.redirect('/admin/blogs');
    } catch (err) {
        console.error(err);
        res.status(500).send('Server Error');
    }
});
  1. 添加博客的路由同理:如果添加博客的表单也有文件上传,同样需要添加upload.any()中间件:
router.post('/blog/add', upload.any(), async (req, res) => {
    // 处理博客添加逻辑
});

额外说明

  • 若只想处理特定文件字段,可替换upload.any()为upload.fields([{name: 'image'}, {name: 'banner_image'}]),精准指定要解析的文件字段。
  • 如果不需要上传文件,也可以直接删除表单的enctype="multipart/form-data"属性,这样express.urlencoded就能正常解析请求体,但会失去文件上传功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:25:52