1. Введение
Когда вы разрабатываете сервис, бывает, что времени на размышления о том, что будет дальше, уходит больше, чем на реализацию интерфейса.
Недавно я столкнулся с таким опытом, разрабатывая функцию обзора для сервиса контента туристических мест.
Функция отзывов позволяет пользователям самостоятельно писать отзывы и загружать фотографии.
Функция сама по себе выглядит относительно простой. Пользователь вводит содержание отзыва и загружает изображение, которое сохраняется на сервере, а затем сохраненные данные отображаются на экране.
Сначала я сосредоточился на том, чтобы обзоры правильно регистрировались и отображались. Но после завершения реализации функций, я вновь рассмотрел это на основе рабочей среды и обнаружил, что возникло гораздо больше вопросов, чем я думал.
-
Что произойдет, если пользователь введет неожиданные строки?
-
Что произойдет, если входные данные будут сохранены в виде HTML-тегов или скриптов?
-
Что будет, если загрузить файл, а не изображение, как изображение?
-
Что произойдет, если информация о файле и фактические сохраненные данные окажутся в разных состояниях во время процесса исправления отзыва?
В среде разработки функции, которые казались без проблем, при взгляде с точки зрения эксплуатации оказались не без недостатков, которые нужно было доработать.
В этой статье мы обсудим, как мы улучшили функционал отзывов.Опыт валидации входных значений, проверки загрузки изображений и управления целостностью данныххочу поделиться.
2. Проблема, обнаруженная в рабочем окружении
Функция отзывов является одной из главных функций, позволяющих пользователям создавать контент самостоятельно.
В отличие от экрана администратора, пользователю трудно предсказать, какие значения вводить, и он может использовать функцию нестандартным образом, не так, как этого ожидал разработчик.
При проверке на основании рабочей среды были обнаружены следующие проблемы.
Особенно функция отзывов представляет собой область, в которую пользователь вводит данные, поэтому необходимо учитывать не только нормальные сценарии использования, но и непредвиденные вводы и исключительные ситуации.
|
Разделитель |
Обнаруженные проблемы |
Влияние |
|---|---|---|
|
Ввод текста |
Строки с одинаковым значением могут храниться в разных формах |
Снижение качества данных |
|
Ввод пользователя |
Возможен ввод в виде HTML-тегов и скриптов |
Риски безопасности и эксплуатации |
|
Загрузка файлов |
Определение изображения только по MIME-типу |
Возможность загрузки неверных файлов |
|
Редактирование изображения |
Информация о файле и данные могут быть несовместимы |
Проблема согласованности данных |
3. Применение проверки входных текстовых значений
Первое, что мы улучшили, это обработка входных значений в тексте отзыва и имени автора.
Сначала мы сохраняли строку, введенную пользователем, как есть.
Однако стало очевидно, что строки с одинаковым значением могут сохраняться в разных форматах в зависимости от способа ввода.
В частности, Широкие символы и полуширокие символывыглядят похоже с точки зрения пользователя, но система распознает их как разные данные.
Если такие данные накапливаются, это может привести к неожиданным проблемам в процессе поиска или управления данными.
Чтобы решить эту проблему, перед сохранением Процесс нормализации строкбыло добавлено.
String normalized = Normalizer.normalize(value, Normalizer.Form.NFKC).trim();
if (normalized.indexOf('<') >= 0 || normalized.indexOf('>') >= 0) {
throw new IllegalArgumentException("Review text cannot contain angle brackets.");
}
NFKC(Нормализация Формы Совместимости Составления)Мы применили это для нормализации строк и внесли изменения, чтобы ограничить сохранение в случае, если символы < и > присутствуют.
Сначала главной целью было предотвращение ввода порнографических фраз или ненужных тегов.
Однако, при проведении обзора, мы также учли возможность сохранения ввода в виде HTML-тегов или скриптов.
Даже если в текущей структуре сервиса немедленно не возникает проблемы, сохранённые данные могут быть использованы на других экранах или функцияхВероятность возникновения проблем, таких как XSS (межсайтовый скриптинг)есть.
В результате эта проверка стала работой, которая учитывает не только простые ограничения на специальные символы, но и качество данных и стабильность обслуживания.
4. Двойная структура проверки во фронтенде и бэкенде
Одной из задач, о которой я задумывался при применении проверки входных значений, было то, где именно проводить эту проверку.
Сначала я думал, что достаточно будет проверить только на бэкенде.
Однако пользователи могли обнаружить ошибки только после нажатия кнопки сохранения, что вызывало разочарование с точки зрения пользовательского опыта.
Поэтому я применил те же правила проверки и на фронтенде.
const hasUnsafeReviewText = (value: string) => {
const normalized = value.normalize('NFKC');
return normalized.includes('<') || normalized.includes('>');
};
На фронтэнде мы реализовали проверку данных сразу после их ввода пользователем для быстрого предоставления обратной связи, а на бэкэнде настроили выполнение финальной проверки по тем же правилам непосредственно перед сохранением.
Роли каждого из областей следующие.
|
раздел |
роль |
|---|---|
|
фронтенд |
Проверка и предоставление обратной связи пользователю сразу после ввода |
|
бэкенд |
Сохранение перед финальной проверкой и защита данных |
После применения этой структуры нам удалось обеспечить как пользовательский опыт, так и стабильность данных.
особенно Поскольку валидации на стороне фронтенда недостаточно для предотвращения прямых вызовов API или обходных запросов, проверка на стороне бэкенда абсолютно необходима.Я смог еще раз подтвердить это.
5. Проверка типа MIME с фактической проверкой изображения
Наиболее сложным аспектом данной работы было подтверждение загрузки изображений.
в начальной реализации файла Проверка только MIME типаЯ делал это.
Например, если передать типы, такие как image/png, image/jpeg, то это будет считаться изображением.
Тогда я думал, что этого достаточно.
Однако в процессе проверки возник вопрос: «Действительно ли файл, переданный как изображение, является изображением?»
MIME тип – это просто информация, передаваемая клиентом, и он не гарантирует фактическое содержимое файла.
Для этого фронтенд был изменен так, чтобы сначала проверять файл на соответствие формата JPEG, PNG, GIF, BMP, проверяя его подпись (Signature).
И в бэкенде добавлена логика проверки, чтобы убедиться, что изображение действительно можно декодировать.
private boolean isDecodableRasterImage(MultipartFile file) {
try (InputStream inputStream = file.getInputStream()) {
BufferedImage image = ImageIO.read(inputStream);
return image != null
&& image.getWidth() > 0
&& image.getHeight() > 0;
} catch (IOException e) {
return false;
}
}
Расширяя критерии валидации с типов MIME на реальные данные изображений, Более надежная защита от загрузки файлов, а не изображенийЯ мог это сделать.
6. Управление целостностью данных при изменении изображения
Лично мне больше всего запомнилось улучшение функции редактирования изображений.
Пользователь может выполнить следующие действия в процессе редактирования отзыва.
-
Сохранение существующего изображения
-
Удаление некоторых существующих изображений
-
Добавление новых изображений
-
Полное удаление существующих изображений
С точки зрения пользователя это выглядит как простая функция редактирования, но на самом деле меняется множество данных.
Файлы, информация об идентификаторе файла (clipId), информация о миниатюре, данные отзывовдолжны всегда оставаться в одном и том же состоянии.
Если изменяется только часть информации, то реальный файл может быть удален, а данные отзывов остаться, или наоборот, данные могут быть удалены, но файл будет продолжать существовать.
Чтобы этого избежать,ясно разграничьте файлы, которые необходимо сохранить, и файлы, которые следует удалить,и упорядочите логику так, чтобы связанные данные также изменялись.
Также была улучшена функция удаления информации о миниатюре и связанных идентификаторах в случае удаления последнего изображения.
Проводя эту работу, я осознал, что поддержание связи между данными может быть важнее, чем реализация функционала.
7. Результаты применения
В результате этих улучшений нам удалось достичь следующего эффекта.
|
Элементы улучшения |
Результаты применения |
|---|---|
|
Нормализация строк |
Улучшение согласованности данных |
|
Блокировка HTML-тегов |
Снижение вероятности возникновения XSS |
|
Усиление проверки изображений |
Предотвращение неправильной загрузки файлов |
|
Двухэтапная проверка на фронте и бэкенде |
Улучшение пользовательского опыта и надежности |
|
Управление целостностью данных |
Снижение несоответствий в информации о файлах |
При отдельном рассмотрении задач это может показаться небольшой правкой.
Но на самом деле в рабочей среде,каждая такая небольшая логика проверки может оказать значительное влияние на качество услуги.яexperimentировал это.
8. Завершение
Во время выполнения этой работы я снова почувствовал, что реализация функций и операционная надежность – это разные аспекты.
Говорить о том, что сервис завершен, только потому что экран работает корректно, было бы неправильно.
Система должна работать надежно, даже если пользователь вводит неожиданные данные, и различные данные должны всегда поддерживаться в согласованном состоянии.
ОсобенноВалидация входных данных и управление целостностью данныхявляются областью, которую пользователи трудно ощутить непосредственно.
Но я считаю, что именно эти невидимые аспекты в конечном итоге определяют качество услуги.
С этим опытом я еще раз почувствовал важность привычки думать не только о реализации функций, но и о том, как данные хранятся и управляются, а также о возможных проблемах, которые могут возникнуть в процессе эксплуатации.
В будущем я намерен продолжать практиковать разработку, учитывающую не только реализацию функций, но и операционную среду.
zero