我正在使用nodejs、ejs 模板、mongodb 和express 创建一个Web 应用程序。我创建了多条路线。对于用户以及其他数据库。我成功地能够从 /register 路由的 post 请求中获取。但无法从 /admin/blog/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/farsaa');
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
这是我的 userRotes.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 User = require('../models/userModel');
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: "afzal", email: 'afzal@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 { title, seo_name, blog_type, author_name, image, banner_image, publish_date, status, trending, long_description } = req.body;
// const updatedBlog = {
// title,
// seo_name,
// blog_type,
// author_name,
// image,
// banner_image,
// publish_date,
// status,
// trending,
// long_description
// };
const userID = req.params.id;
console.log(userID)
// await Blog.findByIdAndUpdate(req.params.id, updatedBlog);
const { title } = req.body;
console.log('Request Body:', req.body); // Log request body
console.log('Update Query:', { title }); // Log update query
// await Blog.findByIdAndUpdate(req.params.id, { title });
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>
<% // - var f = locals.f; %>
<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>
问题是,当我尝试在 /admin/blogs/edit/:id 路径中提交表单时,没有从表单中获取任何数据。 id 已正确获取,但未从正文中获取数据。这是 body req 的 console.log 输出:
id: 65eb8dce672a051114e1a090
Request Body: {}
Update Query: { title: undefined }
问题出在模板中的表单元素:
“方法=“帖子”enctype=“multipart/form-data”>属性
enctype="multipart/form-data"
将表单作为多部分表单数据类型发送,这是上传文件时使用的常用类型,但是服务器上没有可以处理该格式的中间件(常用工具是multer),这这就是为什么 req.body
未定义。
如果您从表单中删除该属性,表单将以 URL 编码类型发送,并且
express.urlencoded
中间件将处理它,您将得到 req.body
。
但是,由于您的表单中有两个文件类型字段,
image
和banner_image
,因此您需要发送多部分类型请求,并且在服务器上,您需要设置多部分中间件,以及文件上传、目的地、命名等
因此,如果您不上传文件,只需删除
enctype="multipart/form-data"
属性即可:
<form action="<%= action %>" method="post" enctype="multipart/form-data">
但是如果你要在服务器上上传文件,你需要设置上传中间件,例如,你可以使用
multer
,这就是你的代码的样子(你需要确定你要如何做处理文件、保存文件的位置、命名等,请参阅链接的文档和示例,它们也在这里使用):
// setup upload middleware
const multer = require('multer');
// setup file destination - you could use in-memory also
const upload = multer({ dest: 'uploads/' });
// you send two file fields, so need to use .fields() method:
const cpUpload = upload.fields([{ name: 'image', maxCount: 1 }, { name: 'banner_image', maxCount: 1 }]);
// add midleware to the route
router.post('/blogs/edit/:id', cpUpload, async (req, res) => {
// handle files, they're in `req.files`
console.log('files', req.files);