- Описание
- Как запустить проект
- Ссылки на проект
- Функциональность
- Технологии, используемые в проекте. Frontend
- Технологии, используемые в проекте. Backend
- Планы по улучшению
Проект Mesto включает фронтенд и бэкенд части веб-приложения со следующими возможностями: авторизации и регистрации пользователей, операции с карточками и пользователями.
В проекте были изучены новые технологии:
- подключение к серверу;
- регистрация пользователя;
- авторизация пользователя;
- вход пользователя по токену, котоый сохраняется в локальном хранилище;
- браузерная валидация форм;
- открытие и закрытие pop up по клику на мышку, кнопку "Esc", фон;
- редактиование и сохранение данных;
- различные pop up;
- Удаление, добавление, лайк карточек;
Фронтенд-часть проекта написана на библиотеке React. Бэкэнд часть проекта написана на JavaScript.
- Скачайте из репозитория https://github.com/milenairon/russian-travel папку, нажав на кнопку Code → Download ZIP
- Извлеките данные из папки.
- Скачайте Node.js
- Войдите через командную строку Node.js в папку с кодом, далее в папку frontend. Введите '''npm run start''' (в браузере откроется front-end часть)
- Войдите через командную строку Node.js в папку backend. Введите '''npm run dev''' (в браузере откроется back-end часть)
Адрес репозитория: https://github.com/milenairon/react-mesto-api-full-gha
Под функциями сайта понимаются возможности:
- возможность зарегистрироваться, а далее авторизироваться на сайте;
- зайти на сайт, минуя страницу "вход в систему", если пользователь уже заходил;
- просмотра тектового материала без перехода на сторонние сайты;
- просмотра тектового материала без перехода на сторонние сайты;
- возможность изменения имени и места работы в сплывающем pop up;
- коректное внесение имени и "о себе", названия картинки и ссылки на нее в сплывающих pop up;
- возможность сохранения свои данных после ввода;
- возможность закрытия страницы без сохранения своих данных разными способами, описанными ранее.
- возможность добавления карточки в сплывающем pop up;
- возможность удаления карточки, а также постановки лайка карточке;
- возможность открытия картинки в большем масштабе в сплывающем pop up;
В проекте были изучены новые технологии:
- подключение к серверу;
- регистрация пользователя;
- авторизация пользователя;
- вход пользователя по токену, котоый сохраняется в локальном хранилище;
- браузерная валидация форм;
- открытие и закрытие pop up по клику на мышку, кнопку "Esc", фон;
- различные pop up;
- редактирование данных и удаление, добавление, лайк карточек;
Для выкладывания работы на сервер я делала следующее:
- В Яндекс.Облако создавала виртуальную машину.
- Выкладывала front-end и back-end части проекта.
- Скачивала зависимости.
- подключала nginx, pm2
- Выпускала сертификаты
Данная технология реализауется через auth запросы. При сабмите формы регистрации отправляется запрос на сервер, в случае его положительного ответа происходит следующее:
- всплывает окно "Вы успешно зарегистрировались";
- сайт переходит на страницу "Вход в систему". При отрицательном ответе(код статуса 400 и другие) реализовано всплывающее окно "что-то пошло не так", в консоли указана причина ошибки(для каждого запроса она имеет свое значение).
Данная технология реализауется через auth запросы. При сабмите формы входа в систему отправляется запрос на сервер, в случае его положительного ответа сайт переходит на страницу с контентом. При отрицательном ответе(код статуса 400, 401 и другие) реализовано всплывающее окно "что-то пошло не так", в консоли указана причина ошибки(для каждого запроса она имеет свое значение).
При входе в систему сохраняем данные (электронную почту и пароль) пользователя в локальном хранилице. Через перехват реакции React.useEffect при загрузки страницы проверяется наличие токена пользователя в выше описанном хранилище, при его наличии пользователь, минуя страницу входа, автоматически переходит на страницу контента.
Данная технология реализуется посредством кода из js документа. Технология представляет собой несколько этапов, содержащих по одной функции на каждое действие. Вкратце это будет звучать так:
- При открытии любого из попапов кнопка сохраниения данных/добавления карточки неактивна.
- При изменении данных профиля/карточки проверяется количество введенных символов(у каждого input свой интервал значений). Также проверяется является ли введенные символы в поле, где должна быть ссылка, сылкой.
- При соответствии всех инпутов данным требованиям в каждой рассматриваемой форме кнопка сохранения/добавления становится активной.
Данная технология реализуется посредством кода из js документа. Ниже представлен пример открытия pop up. Технология представляет собой объявление и присвоение переменной, описание и вызов функции.
jS:
//константа равна открытому попапу
const isSomePopupOpen =
isEditProfilePopupOpen ||
isAddPlacePopupOpen ||
isEditAvatarPopupOpen ||
selectedCard;
//закрытие на темный фон
const handleOverlayClose = React.useCallback((event) => {
if (event.target.classList.contains("popup")) {
/*закрытие всех попапов*/
...
}
}, []);
//закрытие на esc
const handleCloseByEsc = React.useCallback((event) => {
if (event.key === "Escape") {
/*закрытие всех попапов*/
...
}
}, []);
React.useEffect(() => {
if (isSomePopupOpen) {
document.addEventListener("keydown", handleCloseByEsc);
document.addEventListener("click", handleOverlayClose);
return () => {
document.removeEventListener("keydown", handleCloseByEsc);
document.removeEventListener("click", handleOverlayClose);
};
}
}, [isSomePopupOpen]);
Обязательно снимае обработчики после их применения(закрытия попапа), так как нет смысла пользоваться обработчиками закрытия попапа при и так уже закрытом попапе.
Данные технологии реализуется по аналогии с технологиями выше: делается запрос и при положительном его ответе именяется переменная состояния на то, что пришло с сервера/отправляется на сервер и меняется значение в разметке.
Данная технология реализуется посредством кода из js документа. Ниже представлен пример открытия картинки в большем масштабе. Данная часть кода вставляется в App.js с последующей вставкой в основную разметку. При клике на картинку карточке, через пропс card в попапе в значениях ссылки на картинку и имени карточки спрашивается card ? и при положительном ответе вставляется card.name и card.link в соответствующую разметку. Card пробрасывается через пропс в App.js, где его значение меняется через переменную состояния при клике в документе Main.
Данный проект реализуется на базе следующих функций:
- Инфраструктура проекта;
- База данных, контроллеры и роуты для карточек и пользователей;
- Обработка ошибок;
Инфраструктура проекта представляется собой с папками, файлами и основным файлом app.js, а также имеет настроеные
- editorconfig(помогает поддерживать согласованные стили кодирования для нескольких разработчиков, работающих над одним проектом в различных редакторах и IDE),
- линтер(отлавливает ошибки и следит за единообразием кода),
- файлом .gitignore(служит для указания в нём файлов и папок, которые необходимо скрыть от системы контроля версий git) и т.д.
В проекте используется mestodb. В нее записываются карточки и пользователи посредством создания моделей на основе созданных схем. Схема пользователя представляет собой объект из трех составляющих, составленных по типу 'ключ - значение'(name, about, avatar). Схема карточки состоит из 5 составляющих по тому же типу(name, link, owner, likes, createdAt).
Роуты обязательно подключаются в файле app.js, а записываются в папку router, в них используется информация о методах, ссылках запросов и контроллеры, которые записываются в отдельной одноименной папке.
Роуты и контроллеры пользователя могут следующее:
- возвращать всех пользователей,
- возвращать пользователя по id,
- возвращать текущего пользователя,
- обновлять профиль или аватар;
- аутифицировать пользователя,
- зарегистрировать(создать) пользователя.
Роуты и контроллеры карточек могут следующее:
- возвращать все карточки,
- создать карточку,
- удалить карточку по id;
- поставить/убрать лайк.
В случаях, если при запросе что-то пошло не так — вернутся соответствующие коды ошибок: 400 — переданы некорректные данные в методы создания карточки, пользователя, обновления аватара пользователя или профиля; 401 - Отсутствие токена (JWT), некорректный токен (JWT), невалидный пароль; 403 - Обновление чужого профиля, чужого аватара, удаление чужой карточки; 404 — карточка или пользователь не найден; 409 - Попытка зарегистрировать вторую учетную запись на тот же email; 500 — На сервере произошла ошибка.
Безопасность данного сайта представляет собой следующие составляющие:
6.4.1. Защита Авторизацией. Данная технология реализована засчет создания мидлвэра для авторизации, задача которого верифицировать токен и если с ним все в порядке, то добавлять пейлоуд токена в объект запроса.
req.user = payload;
next();
6.4.2. Пароли хэшируются и не возвращаются пользователю в ответе запроса. Хэширование пароля реализовано за счет метода bcrypt.hash. Отсутствие пароля при возврате пользователей в ответе запроса реализовано за счет поля select: false в графе pasword в схеме пользователя.
6.4.3. Безопасный способ хранения JWT в браузере Данные в браузере сохраняются в так называемые куки. Это фрагменты данных, относящихся к определённому домену. Такую куку нельзя прочесть из JavaScript. Токен защищен.
// отправим токен, браузер сохранит его в куках
res
.cookie('jwt', token, {
// token - наш JWT токен, который мы отправляем
maxAge: 3600000,
httpOnly: true
})
.end(); // если у ответа нет тела, можно использовать метод end
6.4.4. Реализована централизованная обработка ошибок Такой способ приводит к тому, что ошибки не дублируются, а в случае отсутствия статуса и сообщения об ошибке, отправляется ошибка со статусом 500 и сообщением "На сервере произошла ошибка".
const getUsers = (req, res, next) => {
// остальной код
.catch((err) => {
next(err);
});
};
module.exports = (error, req, res, next) => {
const { statusCode = 500, message } = error;
res.status(statusCode).send({
message: statusCode === 500 ? "На сервере произошла ошибка." : message,
});
next();
};
6.4.5. Настройка заголовков ответа Заголовки безопасности можно проставлять автоматически — для этого есть модуль Helmet:
const helmet = require('helmet');
app.use(helmet());
6.4.6. Защита от брутфорсу и DDоSу Чтобы защититься от множества автоматических запросов, существует специальный мидлвэр — express-rate-limit:
const express = require('express');
const rateLimit = require('express-rate-limit');
const app = express();
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // за 15 минут
max: 100 // можно совершить максимум 100 запросов с одного IP
});
// подключаем rate-limiter
app.use(limiter);
Валидация данного сайта представляет собой следующие составляющие:
6.5.1. Валидация приходящих на сервер запросов; Тела запросов к серверу валидируются до передачи обработки в контроллеры. Если запрос принимает какую-то информацию в заголовках или параметрах, она валидируется. API возвращает ошибку, если запрос не соответствует схеме.
6.5.2. Валидация данных на уровне схемы Валидация данных на уровне схемы просиходит следующим образом:
const userSchema = new mongoose.Schema(
{
...
// информация о пользователе
about: {
type: String,
minlength: [2, "Описание не должно быть короче 2-х символов"],
maxlength: [30, "Описание не должно быть длиннее 30-и символов"],
default: "Исследователь",
},
// ссылка на аватарку
avatar: {
type: String,
default:
"https://pictures.s3.yandex.net/resources/jacques-cousteau_1604399756.png",
validate: {
validator: (avatar) => {
/https?:\/\/(www\.)?[a-zA-Z0-9-@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([a-zA-Z0-9()-@:%_+.~#?&//=]*)/.test(
avatar
);
},
message: "Передан некорректный электронный адрес",
},
},
...}
);
- Дополнительная валидация, изменение текста ошибок
- Фильтр карточек
- Валидация ссылок картинок
- Наделение правами администратора одного пользователя
- Дополнительные страницы для администратора
