Web · Урок 23

Формы, валидация и файлы

Регистрация, заказ, комментарий — всё начинается с формы. Соберём данные, проверим их и доведём до сервера. И разберём загрузку файлов — тот самый multipart/form-data.

Разметка формы

Атрибуты required, type и pattern дают первичную проверку ещё до отправки, без единой строчки JS.

<form id="order">
  <label>Имя
    <input name="name" required>
  </label>
  <label>Email
    <input type="email" name="email" required>
  </label>
  <label>Телефон (10 цифр)
    <input name="phone" pattern="\d{10}">
  </label>
  <button type="submit">Отправить</button>
</form>

Валидация на клиенте и на сервере

Клиентская проверка — для удобства: мгновенный отклик, без перезагрузки. Серверная — для истины: браузер можно обойти одной строкой, а данные всё равно придут. Поэтому проверяем в обоих местах.

document.getElementById("order").addEventListener("submit", async (e) => {
  e.preventDefault();
  const fd = new FormData(e.target);
  const data = Object.fromEntries(fd);

  if (!data.name || !/.+@.+\..+/.test(data.email)) {
    alert("Заполните форму корректно");
    return;
  }

  const res = await fetch("/api/order", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data)
  });
});
⚠️
pattern и проверка в JS — украшение. На сервере всё повторяем снова и строим ответы с понятными сообщениями об ошибках. Доверять клиенту данные нельзя — это его данные, а не ваша.

Сервер принимает данные

app.use(express.json());

app.post("/api/order", (req, res) => {
  const { name, email, phone } = req.body;

  if (!name || !/^.+@.+\..+$/.test(email)) {
    return res.status(400).json({ error: "Некорректные данные" });
  }

  // тут — сохранение в базу (урок 22)
  res.status(201).json({ ok: true });
});

Загрузка файлов

Файлы передаются иначе, чем JSON: потоком в multipart/form-data. На сервере Express спасает пакет multer.

npm install multer

const multer = require("multer");
const upload = multer({ dest: "uploads/" });

app.post("/upload", upload.single("avatar"), (req, res) => {
  // req.file — метаданные сохранённого файла
  res.json({ file: req.file.filename });
});
💡
Никогда не отдавайте пользовательские файлы как есть «по имени». Присваивайте случайное имя, проверяйте расширение и размер, храните вне папки публичной статики.