Другое

Как отображать сообщения об ошибках в Node.js MySQL EJS без запросов к базе данных

Узнайте, как отображать сообщения об ошибках в Node.js, MySQL и EJS без лишних запросов к базе данных. Сохраняйте данные формы во время валидации с помощью хранилища сессий и flash-сообщений для эффективной обработки ошибок.

Как отображать сообщения об ошибках в Node.js, MySQL и EJS без выполнения ненужных запросов к базе данных? Я разрабатываю биллинговое приложение, где мне необходимо проверять отправку форм, чтобы убедиться, что значения количества не равны нулю. Когда проверка не проходит, я хочу отображать сообщение об ошибке, сохраняя при этом существующие данные о продуктах из базы данных. В настоящее время, когда я отображаю страницу ошибки с помощью res.render('viewbill.ejs', {errormessage: errormessage}), существующие данные о продуктах теряются. Можно ли избежать повторного запроса к базе данных только для отображения сообщения об ошибке? Кроме того, я ищу универсальный подход к обработке ошибок с использованием частичных шаблонов, который можно повторно использовать на разных страницах моего приложения Node.js.

Вы можете сохранять существующие данные продукта во время ошибок проверки формы, используя хранилище сессий в сочетании с flash-сообщениями и частичными шаблонами. Этот подход позволяет проверять отправки форм без повторного запроса к базе данных при сбое проверки, при этом сохраняя многоразовую систему обработки ошибок во всем вашем приложении.

Содержание

Понимание проблемы

В вашем биллинговом приложении, когда вы проверяете отправки форм (например, проверяете, что значения количества не равны нулю) и сталкиваетесь с ошибками проверки, вы сталкиваетесь с распространенной проблемой: потеря существующих данных продукта при отображении страниц с ошибками. Это происходит потому, что:

  • Вызов res.render() передает только сообщение об ошибке
  • Данные продукта, хранящиеся в переменных, теряются во время перенаправления
  • Повторный запрос к базе данных просто для отображения тех же данных неэффективен

Решение включает сохранение данных формы между запросами и реализацию многоразовой обработки ошибок, которая работает на разных страницах без обращений к базе данных.

Подход с использованием Flash-сообщений

Flash-сообщения обеспечивают способ передачи данных между запросами, делая их идеальными для обработки ошибок в приложениях Node.js.

Необходимая настройка

javascript
// 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-сообщений для ошибок проверки

javascript
// В обработчике отправки формы
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

html
<!-- В вашем шаблоне формы -->
<% 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-сообщения работают для простых случаев, хранилище сессий обеспечивает более комплексное сохранение данных.

Расширенный подход на основе сессии

javascript
// 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

html
<!-- В вашем шаблоне формы -->
<% 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>
<% } %>

Частичные шаблоны для обработки ошибок

Создание многоразовых компонентов обработки ошибок, которые можно использовать на разных страницах.

Создание частичного шаблона ошибки

html
<!-- 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>
<% } %>

Создание частичного шаблона данных формы

html
<!-- 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>
<% } %>

Использование частичных шаблонов в ваших шаблонах

html
<!-- В вашем основном шаблоне -->
<%- include('partials/error-message') %>
<%- include('partials/form-data') %>

<!-- Содержимое вашей формы -->
<form action="/addbill" method="POST">
  <!-- Поля формы -->
</form>

Полный пример реализации

Вот полный пример, который решает все аспекты вашей проблемы:

Реализация на стороне сервера

javascript
// 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 с интеграцией частичных шаблонов

html
<!-- 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. Обязательная серверная проверка

Даже если вы реализуете клиентскую проверку, всегда проверяйте на стороне сервера:

javascript
// Всегда проверяйте на стороне сервера
if (parseInt(req.body.quantity) <= 0) {
  req.flash('error', 'Количество должно быть больше нуля');
  return res.redirect('/addbill');
}

2. Используйте express-validator для сложной проверки

javascript
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. Реализуйте правильную очистку сессии

javascript
// Очистка данных сессии после успешных операций
app.post('/addbill', (req, res) => {
  // ... логика проверки
  
  if (validationPasses) {
    req.session.formData = null; // Очистка данных формы
    req.session.validationErrors = null; // Очистка сохраненных ошибок
    // ... продолжение с операцией базы данных
  }
});

4. Используйте AJAX для проверки в реальном времени (опционально)

Для лучшего пользовательского опыта рассмотрите проверку через AJAX:

javascript
// 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 обработки ошибок

javascript
// Глобальный обработчик ошибок
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  // Сохранение ошибки в сессии
  req.flash('error', 'Произошла непредвиденная ошибка');
  req.session.formData = req.body;
  
  res.redirect('/addbill');
});

Реализуя эти решения, вы сможете:

  • Отображать сообщения об ошибках без потери существующих данных продукта
  • Избегать ненужных обращений к базе данных при сбоях проверки
  • Создавать многоразовые компоненты обработки ошибок, работающие согласованно во всем приложении
  • Предоставлять лучший пользовательский опыт с сохраненным состоянием формы

Ключевым является использование хранилища сессий для сохранения данных формы между запросами и flash-сообщений для передачи информации об ошибках, при этом используя частичные шаблоны EJS для многоразовых компонентов, работающих согласованно во всем приложении.

Источники

  1. Проверка формы и отображение сообщений об ошибках с использованием ejs - Stack Overflow
  2. Как использовать req.flash() с EJS? - Stack Overflow
  3. Отображение Flash-сообщений Node.js с использованием EJS - Raddy
  4. Flash-сообщение из ejs в Express 4 - Stack Overflow
  5. Проверка формы в NodeJS – Tanmay Sarkar
  6. Как использовать Embedded JavaScript (EJS) в Node.js - Squash.io
  7. Проверка и обработка ошибок в Express - Mannhowie

Заключение

  • Используйте хранилище сессий для сохранения данных формы между запросами проверки, устраняя необходимость повторного запроса к базе данных
  • Реализуйте flash-сообщения с connect-flash для передачи информации об ошибках через HTTP-запросы
  • Создавайте частичные шаблоны EJS для многоразовых компонентов обработки ошибок, работающих согласованно на разных страницах
  • Всегда выполняйте серверную проверку, даже при использовании клиентской проверки для безопасности
  • Реализуйте правильную очистку сессии для предотвращения утечек памяти и обеспечения свежести данных
  • Рассмотрите проверку через AJAX для обратной связи в реальном времени без полной перезагрузки страницы

Этот подход дает вам надежное, масштабируемое решение для проверки формы, которое поддерживает пользовательский опыт, оптимизируя использование базы данных.

Авторы
Проверено модерацией
Модерация