Как отображать сообщения об ошибках в Node.js MySQL EJS без запросов к базе данных
Узнайте, как отображать сообщения об ошибках в Node.js, MySQL и EJS без лишних запросов к базе данных. Сохраняйте данные формы во время валидации с помощью хранилища сессий и flash-сообщений для эффективной обработки ошибок.
Как отображать сообщения об ошибках в Node.js, MySQL и EJS без выполнения ненужных запросов к базе данных? Я разрабатываю биллинговое приложение, где мне необходимо проверять отправку форм, чтобы убедиться, что значения количества не равны нулю. Когда проверка не проходит, я хочу отображать сообщение об ошибке, сохраняя при этом существующие данные о продуктах из базы данных. В настоящее время, когда я отображаю страницу ошибки с помощью res.render('viewbill.ejs', {errormessage: errormessage}), существующие данные о продуктах теряются. Можно ли избежать повторного запроса к базе данных только для отображения сообщения об ошибке? Кроме того, я ищу универсальный подход к обработке ошибок с использованием частичных шаблонов, который можно повторно использовать на разных страницах моего приложения Node.js.
Вы можете сохранять существующие данные продукта во время ошибок проверки формы, используя хранилище сессий в сочетании с flash-сообщениями и частичными шаблонами. Этот подход позволяет проверять отправки форм без повторного запроса к базе данных при сбое проверки, при этом сохраняя многоразовую систему обработки ошибок во всем вашем приложении.
Содержание
- Понимание проблемы
- Подход с использованием Flash-сообщений
- Решение с использованием хранилища сессий
- Частичные шаблоны для обработки ошибок
- Полный пример реализации
- Лучшие практики
Понимание проблемы
В вашем биллинговом приложении, когда вы проверяете отправки форм (например, проверяете, что значения количества не равны нулю) и сталкиваетесь с ошибками проверки, вы сталкиваетесь с распространенной проблемой: потеря существующих данных продукта при отображении страниц с ошибками. Это происходит потому, что:
- Вызов
res.render()передает только сообщение об ошибке - Данные продукта, хранящиеся в переменных, теряются во время перенаправления
- Повторный запрос к базе данных просто для отображения тех же данных неэффективен
Решение включает сохранение данных формы между запросами и реализацию многоразовой обработки ошибок, которая работает на разных страницах без обращений к базе данных.
Подход с использованием Flash-сообщений
Flash-сообщения обеспечивают способ передачи данных между запросами, делая их идеальными для обработки ошибок в приложениях Node.js.
Необходимая настройка
// app.js
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const flash = require('connect-flash');
const app = express();
// Конфигурация сессии
app.use(cookieParser());
app.use(session({
secret: 'ваш-секретный-ключ',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 7200000 } // 2 часа
}));
app.use(flash());
Использование Flash-сообщений для ошибок проверки
// В обработчике отправки формы
app.post('/addbill', (req, res) => {
const { quantity, productName, price } = req.body;
// Серверная проверка
if (quantity == 0) {
req.flash('error', 'Количество не может быть равно нулю');
req.flash('formData', req.body); // Сохранение данных формы
return res.redirect('/addbill'); // Перенаправление на страницу формы
}
// Если проверка пройдена, продолжаем с операцией базы данных
// ... ваша логика базы данных здесь
});
Отображение Flash-сообщений в EJS
<!-- В вашем шаблоне формы -->
<% if (messages.error) { %>
<div class="alert alert-danger">
<%= messages.error %>
</div>
<% } %>
<!-- Предварительное заполнение формы предыдущими данными -->
<% if (messages.formData) { %>
<input type="number" name="quantity" value="<%= messages.formData.quantity || '' %>">
<input type="text" name="productName" value="<%= messages.formData.productName || '' %>">
<% } %>
Решение с использованием хранилища сессий
Хотя flash-сообщения работают для простых случаев, хранилище сессий обеспечивает более комплексное сохранение данных.
Расширенный подход на основе сессии
// Middleware для хранения данных формы в сессии
app.use((req, res, next) => {
if (!req.session.formData) {
req.session.formData = {};
}
next();
});
// В вашем обработчике формы
app.post('/addbill', (req, res) => {
// Сохранение текущих данных формы в сессии
req.session.formData = req.body;
if (req.body.quantity == 0) {
req.flash('error', 'Количество не может быть равно нулю');
return res.redirect('/addbill');
}
// Очистка данных сессии при успешной отправке
req.session.formData = null;
// ... продолжаем с операцией базы данных
});
Получение данных сессии в EJS
<!-- В вашем шаблоне формы -->
<% if (session && session.formData) { %>
<form action="/addbill" method="POST">
<input type="number" name="quantity"
value="<%= session.formData.quantity || '' %>">
<input type="text" name="productName"
value="<%= session.formData.productName || '' %>">
<!-- Другие поля формы -->
</form>
<% } %>
Частичные шаблоны для обработки ошибок
Создание многоразовых компонентов обработки ошибок, которые можно использовать на разных страницах.
Создание частичного шаблона ошибки
<!-- partials/error-message.ejs -->
<% if (messages && messages.error) { %>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Ошибка:</strong> <%= messages.error %>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
</div>
<% } %>
<% if (errors && errors.length > 0) { %>
<div class="alert alert-danger">
<ul>
<% errors.forEach(function(error) { %>
<li><%= error.msg %></li>
<% }); %>
</ul>
</div>
<% } %>
Создание частичного шаблона данных формы
<!-- partials/form-data.ejs -->
<% if (session && session.formData) { %>
<script>
// Автоматическое заполнение полей формы данными из сессии
document.addEventListener('DOMContentLoaded', function() {
<% for (var field in session.formData) { %>
var fieldElement = document.querySelector('[name="<%= field %>"]');
if (fieldElement) {
fieldElement.value = '<%= session.formData[field] %>';
}
<% } %>
});
</script>
<% } %>
Использование частичных шаблонов в ваших шаблонах
<!-- В вашем основном шаблоне -->
<%- include('partials/error-message') %>
<%- include('partials/form-data') %>
<!-- Содержимое вашей формы -->
<form action="/addbill" method="POST">
<!-- Поля формы -->
</form>
Полный пример реализации
Вот полный пример, который решает все аспекты вашей проблемы:
Реализация на стороне сервера
// app.js
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const flash = require('connect-flash');
const bodyParser = require('body-parser');
const app = express();
// Настройка middleware
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: 'ваш-секретный-ключ',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 7200000 }
}));
app.use(flash());
// Глобальные переменные для всех представлений
app.use((req, res, next) => {
res.locals.messages = req.flash();
res.locals.session = req.session;
next();
});
// Маршрут формы - GET
app.get('/addbill', (req, res) => {
// Получение существующих продуктов из базы данных (только если их нет в сессии)
if (!req.session.formData || Object.keys(req.session.formData).length === 0) {
// Ваш запрос к базе данных для получения продуктов
// Product.find({}, (err, products) => {
// res.render('addbill', { products: products });
// });
} else {
// Использование данных сессии вместо запроса к базе данных
res.render('addbill', {
products: req.session.savedProducts || [],
formData: req.session.formData
});
}
});
// Отправка формы - POST
app.post('/addbill', (req, res) => {
const { quantity, productName, price } = req.body;
// Сохранение данных формы в сессии
req.session.formData = req.body;
// Проверки валидации
const errors = [];
if (quantity == 0) {
errors.push('Количество не может быть равно нулю');
}
if (!productName || productName.trim() === '') {
errors.push('Название продукта обязательно');
}
if (errors.length > 0) {
req.flash('error', errors.join(', '));
return res.redirect('/addbill');
}
// Очистка данных сессии при успешной проверке
req.session.formData = null;
// Продолжение с операцией базы данных
// ... ваша логика MySQL здесь
// Сохранение продуктов в сессию для следующего запроса
req.session.savedProducts = savedProducts; // Предполагаем, что у вас есть это из вашей базы данных
req.flash('success', 'Счет успешно добавлен');
res.redirect('/addbill');
});
Шаблон EJS с интеграцией частичных шаблонов
<!-- views/addbill.ejs -->
<!DOCTYPE html>
<html>
<head>
<title>Добавить счет</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Добавить счет</h1>
<!-- Включение частичного шаблона ошибки -->
<%- include('partials/error-message') %>
<!-- Сообщение об успехе -->
<% if (messages.success) { %>
<div class="alert alert-success">
<%= messages.success %>
</div>
<% } %>
<form action="/addbill" method="POST">
<div class="mb-3">
<label for="productName" class="form-label">Название продукта</label>
<input type="text" class="form-control" id="productName" name="productName" required>
</div>
<div class="mb-3">
<label for="quantity" class="form-label">Количество</label>
<input type="number" class="form-control" id="quantity" name="quantity" min="1" required>
</div>
<div class="mb-3">
<label for="price" class="form-label">Цена</label>
<input type="number" class="form-control" id="price" name="price" step="0.01" required>
</div>
<button type="submit" class="btn btn-primary">Добавить счет</button>
</form>
<!-- Отображение существующих продуктов -->
<% if (products && products.length > 0) { %>
<h3>Существующие продукты</h3>
<table class="table">
<thead>
<tr>
<th>Название продукта</th>
<th>Количество</th>
<th>Цена</th>
</tr>
</thead>
<tbody>
<% products.forEach(function(product) { %>
<tr>
<td><%= product.name %></td>
<td><%= product.quantity %></td>
<td><%= product.price %></td>
</tr>
<% }); %>
</tbody>
</table>
<% } %>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Лучшие практики
1. Обязательная серверная проверка
Даже если вы реализуете клиентскую проверку, всегда проверяйте на стороне сервера:
// Всегда проверяйте на стороне сервера
if (parseInt(req.body.quantity) <= 0) {
req.flash('error', 'Количество должно быть больше нуля');
return res.redirect('/addbill');
}
2. Используйте express-validator для сложной проверки
const { body, validationResult } = require('express-validator');
app.post('/addbill', [
body('quantity').isInt({ min: 1 }).withMessage('Количество должно быть не менее 1'),
body('productName').notEmpty().withMessage('Название продукта обязательно')
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('error', errors.array().map(e => e.msg).join(', '));
req.session.formData = req.body;
return res.redirect('/addbill');
}
// Продолжение с операцией базы данных
});
3. Реализуйте правильную очистку сессии
// Очистка данных сессии после успешных операций
app.post('/addbill', (req, res) => {
// ... логика проверки
if (validationPasses) {
req.session.formData = null; // Очистка данных формы
req.session.validationErrors = null; // Очистка сохраненных ошибок
// ... продолжение с операцией базы данных
}
});
4. Используйте AJAX для проверки в реальном времени (опционально)
Для лучшего пользовательского опыта рассмотрите проверку через AJAX:
// JavaScript на стороне клиента
document.querySelector('form').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('/validate-form', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.isValid) {
this.submit(); // Отправка формы
} else {
// Отображение сообщения об ошибке
document.getElementById('error-message').textContent = result.error;
}
} catch (error) {
console.error('Ошибка проверки:', error);
}
});
5. Реализуйте глобальный middleware обработки ошибок
// Глобальный обработчик ошибок
app.use((err, req, res, next) => {
console.error(err.stack);
// Сохранение ошибки в сессии
req.flash('error', 'Произошла непредвиденная ошибка');
req.session.formData = req.body;
res.redirect('/addbill');
});
Реализуя эти решения, вы сможете:
- Отображать сообщения об ошибках без потери существующих данных продукта
- Избегать ненужных обращений к базе данных при сбоях проверки
- Создавать многоразовые компоненты обработки ошибок, работающие согласованно во всем приложении
- Предоставлять лучший пользовательский опыт с сохраненным состоянием формы
Ключевым является использование хранилища сессий для сохранения данных формы между запросами и flash-сообщений для передачи информации об ошибках, при этом используя частичные шаблоны EJS для многоразовых компонентов, работающих согласованно во всем приложении.
Источники
- Проверка формы и отображение сообщений об ошибках с использованием ejs - Stack Overflow
- Как использовать req.flash() с EJS? - Stack Overflow
- Отображение Flash-сообщений Node.js с использованием EJS - Raddy
- Flash-сообщение из ejs в Express 4 - Stack Overflow
- Проверка формы в NodeJS – Tanmay Sarkar
- Как использовать Embedded JavaScript (EJS) в Node.js - Squash.io
- Проверка и обработка ошибок в Express - Mannhowie
Заключение
- Используйте хранилище сессий для сохранения данных формы между запросами проверки, устраняя необходимость повторного запроса к базе данных
- Реализуйте flash-сообщения с connect-flash для передачи информации об ошибках через HTTP-запросы
- Создавайте частичные шаблоны EJS для многоразовых компонентов обработки ошибок, работающих согласованно на разных страницах
- Всегда выполняйте серверную проверку, даже при использовании клиентской проверки для безопасности
- Реализуйте правильную очистку сессии для предотвращения утечек памяти и обеспечения свежести данных
- Рассмотрите проверку через AJAX для обратной связи в реальном времени без полной перезагрузки страницы
Этот подход дает вам надежное, масштабируемое решение для проверки формы, которое поддерживает пользовательский опыт, оптимизируя использование базы данных.