JS: Веб-разработка

Теория: Модифицирующие формы

В этом уроке мы изучим формы, которые меняют данные. И с клиентской, и с серверной стороны они обычно устроены сложнее, чем поисковые формы. Для уверенной работы с ними нужно разбираться:

  • Как работают соответствующие HTML-теги
  • Как отправляются формы по HTTP
  • Как происходит обработка на стороне сервера
  • Как работает валидация и вывод ошибок

Все это мы изучим в ближайшее время.

Вывод формы

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

  • GET /users/new — страница с формой, которую заполняет пользователь. Эта форма отправляет POST-запрос на адрес /users, указанный в атрибуте action
  • POST /users — маршрут, обрабатывающий данные формы

Добавим обработчик маршрута /users/new, который выводит форму добавления пользователя:

app.get('/users/new', (req, res) => {
  res.view('src/views/users/new')
})

Создадим форму в файле src/views/users/new.pug

html
  body
    form(action = '/users', method = 'post')
      div
        label Имя:
          input(type = 'text', name = 'name')
      div
        label Email:
          input(type = 'email', name = 'email', required = true)
      div
        label Пароль:
          input(type = 'password', name = 'password', required = true)
      div
        label Подтверждение пароля:
          input(type = 'password', name = 'passwordConfirmation', required = true)
      input(type = 'submit', value = 'Зарегистрировать')

Запустите сервер и убедитесь, что форма выводится по адресу /users/new. Если ее заполнить и попытаться отправить, то браузер сформирует следующий HTTP-запрос:

# Данные взяты для примера

POST /users HTTP/1.1
Host: localhost
Content-type: application/x-www-form-urlencoded
Content-length: 76

name=Mike&email=example@test.com&password=qwerty&passwordConfirmation=qwerty

В примере выше мы видели работу с HTTP, но на практике все устроено немного по-другому. Не стоит передавать электронную почту, пароль и другие чувствительные данные по обычному HTTP-протоколу, потому что так данные легко перехватить и использовать не по назначению.

Именно поэтому современные сайты обычно работают по протоколу HTTPS, который передает данные в зашифрованном виде.

Обработка данных

Форма готова, теперь можно реализовывать ее обработчик. Обработчик формы работает так:

  • Извлекает параметры формы
  • Формирует объект пользователя на основе этих параметров
  • Сохраняет пользователя в базу данных
  • Выполняет редирект — например, на страницу пользователей

Все данные приходят в виде строки. Удобнее всего добавить плагин, который будет помогать парсить тело запроса. Для этого устанавливаем нужный пакет:

npm i @fastify/formbody

И подключаем плагин в приложение:

import fastify from 'fastify'
import formbody from '@fastify/formbody'

const app = fastify()

await app.register(formbody)

Код обработчика выглядит так:

app.post('/users', (req, res) => {
  const user = {
    name: req.body.name,
    email: req.body.email,
    password: req.body.password,
  }

  state.users.push(user)

  res.redirect('/users')
})

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

Нормализация данных

Представим, что при регистрации пользователь написал свою почту в произвольном регистре — MYname@example.com вместо myname@example.com. По спецификации, адреса электронной почты не зависят от регистра. Другими словами, если в двух адресах совпадают буквы, то они считаются одним и тем же адресом.

Проблема в том, что с точки зрения кода и большинства баз данных мы сравниваем строки с учетом регистра. В итоге наш проект ждут два сюрприза:

  • Пользователь сможет зарегистрировать несколько аккаунтов на один и тот же адрес почты, просто вводя адрес в разном регистре
  • Пользователь не сможет зайти на сайт, если введет почту не в том регистре, который использовал при регистрации

Чтобы этого не происходило, введенные пользователями данные проходят нормализацию. В случае почты мы приводим ее к нижнему регистру:

// Касается только емейла
const user = {
  name: req.body.name,
  email: req.body.email.toLowerCase(),
  password: req.body.password,
}

Пользователь может не только ошибиться в регистре, но и случайно поставить пробелы в конце или в начале строк — например, из-за копирования. Иногда мы не можем на это влиять. Например, пользователь может специально добавить пробельный символ в начале и конце пароля.

А вот для имени и адреса почты такое недопустимо. Поэтому лучше обрезать концевые пробелы для надежности:

const user = {
  name: req.body.name.trim(),
  email: req.body.email.trim().toLowerCase(),
  password: req.body.password,
}

Завершено

0 / 23