Наличие ошибок в коде страницы сайта всегда влечет за собой негативные последствия – от ухудшения позиций в ранжировании до жалоб со стороны пользователей. Ошибки валидации могут наблюдаться как на главной, так и на иных веб-страницах, их наличие свидетельствует о том, что ресурс является невалидным. Некоторые проблемы замечают даже неподготовленные пользователи, другие невозможно обнаружить без предварительного аудита, анализа. О том, что такое ошибки валидации и как их обнаружить, мы сейчас расскажем.
Ошибка валидации, что это такое?
Для написания страниц используется HTML – стандартизированный язык разметки, применяемый в веб-разработке. HTML, как любой другой язык, имеет специфические особенности синтаксиса, грамматики и т. д. Если во время написания кода правила не учитываются, то после запуска сайта будут появляться различные виды проблем. Если HTML-код ресурса не соответствует стандарту W3C, то он является невалидным, о чем мы писали выше.
Почему ошибки валидации сайта оказывают влияние на ранжирование, восприятие?
Наличие погрешностей в коде – проблема, с которой необходимо бороться сразу после обнаружения. Поисковые системы «читают» HTML-код, если он некорректный, то процесс индексации и ранжирования может быть затруднен. Поисковые роботы должны понимать, каким является ресурс, что он предлагает, какие запросы использует. Особо критичны такие ситуации для ресурсов, имеющих большое количество веб-страниц.
Как проверить ошибки валидации?
Для этой работы используется либо технический аудит сайта, либо валидаторы, которые ищут проблемы автоматически. Одним из самых популярных является сервис The W3C Markup Validation Service, выполняющий сканирование с оглядкой на World Wide Web Consortium (W3C). Рассматриваемый валидатор предлагает три способа, с помощью которых можно осуществить проверку сайта:
- ввод URL-адреса страниц, которые необходимо просканировать;
- загрузка файла страницы;
- ввод части HTML-кода, нуждающегося в проверке.
После завершения проверки вы получите развернутый список выявленных проблем, дополненных описанием, ссылками на стандарты W3C. По ходу анализа вы увидите слабые места со ссылками на правила, что позволит самостоятельно исправить проблему.
Существуют другие сервисы, позволяющие выполнить проверку валидности кода:
- Dr. Watson. Проверяет скорость загрузки страниц, орфографию, ссылки, а также исходный код;
- InternetSupervision.com. Отслеживает производительность сайта, проверяет доступность HTML.
Плагины для браузеров, которые помогут найти ошибки в коде
Решить рассматриваемую задачу можно с помощью плагинов, адаптированных под конкретный браузер. Можно использовать следующие инструменты (бесплатные):
- HTML Validator для браузера Firefox;
- HTML Validator for Chrome;
- Validate HTML для Firefox.
После проверки нужно решить, будете ли вы устранять выявленные ошибки. Многие эксперты акцентируют внимание на том, что поисковые системы сегодня уделяют больше внимания качеству внешней/внутренней оптимизации, контенту, другим характеристикам. Однако валидность нельзя оставлять без внимания, ведь если даже обнаруженные проблемы не будут мешать поисковым ботам, то они точно начнут раздражать посетителей сайта.
Как исправить ошибку валидации?
В первую очередь нужно сосредоточить внимание на слабых местах, связанных с контентом – это то, что важно для поисковых систем. Если во время сканирования было выявлено более 25 проблем, то их нельзя игнорировать из-за ряда причин:
- частичная индексация;
- медленная загрузка;
- баги, возникающие во время непосредственной коммуникации пользователя с ресурсом.
Например, игнорирование ошибок может привести к тому, что некоторые страницы не будут проиндексированы. Для решения рассматриваемой проблемы можно привлечь опытного фрилансера, однако лучшее решение – заказ услуги в веб-агентстве, что позволит исправить, а не усугубить ситуацию.
Технический и SEO-аудит
Выявление ошибок – первый шаг, ведь их еще нужно будет устранить. При наличии большого пула проблем целесообразно заказать профессиональный аудит сайта. Он поможет найти разные виды ошибок, повысит привлекательность ресурса для поисковых ботов, обычных пользователей: скорость загрузки страниц, верстка, переспам, другое.
В заключение
На всех сайтах наблюдаются ошибки валидации – их невозможно искоренить полностью, но и оставлять без внимания не стоит. Например, если провести проверку сайтов Google или «Яндекс», то можно увидеть ошибки, однако это не означает, что стоит вздохнуть спокойно и закрыть глаза на происходящее. Владелец сайта должен ставить во главу угла комплексное развитие, при таком подходе ресурс будет наполняться, обновляться и «лечиться» своевременно. Если проблем мало, то можно попробовать устранить их своими силами или с помощью привлечения стороннего частного специалиста. В остальных случаях лучше заказать услугу у проверенного подрядчика.
Просмотров 1.2к. Опубликовано 19.12.2022
Обновлено 19.12.2022
Каждый сайт, который создает компания, должен отвечать принятым стандартам. В первую очередь затем, чтобы он попадал в поисковую выдачу и был удобен для пользователей. Если код страниц содержит ошибки, неточности, он становится “невалидным”, то есть не соответствующим требованиям. В результате интернет-ресурс не увидят пользователи или информация на нем будет отображаться некорректно.
В этой статье рассмотрим, что такое валидность, какие могут быть ошибки в HTML-разметке и как их устранить.
Содержание
- Что такое HTML-ошибка валидации и зачем она нужна
- Чем опасны ошибки в разметке
- Как проверить ошибки валидации
- Предупреждения
- Ошибки
- Пример прохождения валидации для страницы сайта
- Как исправить ошибку валидации
- Плагины для браузеров, которые помогут найти ошибки в коде
- Коротко о главном
Что такое HTML-ошибка валидации и зачем она нужна
Под понятием “валидация” подразумевается процесс онлайн-проверки HTML-кода страницы на соответствие стандартам w3c. Эти стандарты были разработаны Организацией всемирной паутины и стандартов качества разметки. Сама организация продвигает идею унификации сайтов по HTML-коду — чтобы каждому пользователю, вне зависимости от браузера или устройства, было удобно использовать ресурс.
Если код отвечает стандартам, то его называют валидным. Браузеры могут его прочитать, загрузить страницы, а поисковые системы легко находят страницу по соответствующему запросу.
Чем опасны ошибки в разметке
Ошибки валидации могут разными — видимыми для глаза простого пользователя или такими, которые можно засечь только с помощью специальных программ. В первом случае кроме технических проблем, ошибки в разметке приводят к негативному пользовательскому опыту.
К наиболее распространённым последствиям ошибок в коде HTML-разметки также относят сбои в нормальной работе сайта и помехи в продвижении ресурса в поисковых системах.
Рассмотрим несколько примеров, как ошибки могут проявляться при работе:
- Медленно подгружается страница
Согласно исследованию Unbounce, более четверти пользователей покидают страницу, если её загрузка занимает более 3 секунд, ещё треть уходит после 6 секунд;
- Не видна часть текстовых, фото и видео-блоков
Эта проблема делает контент для пользователей неинформативным, поэтому они в большинстве случаев уходят со страницы, не досмотрев её до конца;
- Страница может остаться не проиндексированной
Если поисковый робот распознает недочёт в разметке, он может пропустить страницу и прервать её размещение в поисковых системах;
- Разное отображение страниц на разных устройствах
Например, на компьютере или ноутбуке страница будет выглядеть хорошо, а на мобильных гаджетах половина кнопок и изображений будет попросту не видна.
Из-за этих ошибок пользователь не сможет нормально работать с ресурсом. Единственное решение для него — закрыть вкладку и найти нужную информацию на другом сайте. Так количество посетителей сайта постепенно уменьшается, он перестает попадать в поисковую выдачу — в результате ресурс становится бесполезным и пропадает в пучине Интернета.
Как проверить ошибки валидации
Владельцы ресурсов используют 2 способа онлайн-проверки сайтов на наличие ошибок — технический аудит или использование валидаторов.
Первый случай подходит для серьёзных проблем и масштабных сайтов. Валидаторами же пользуются ежедневно. Наиболее популярный — сервис The W3C Markup Validation Service. Он сканирует сайт и сравнивает код на соответствие стандартам W3C. Валидатор выдаёт 2 типа несоответствий разметки стандартам W3C: предупреждения и ошибки.
Давайте рассмотрим каждый из типов чуть подробнее.
Предупреждения
Предупреждения отмечают незначительные проблемы, которые не влияют на работу ресурса. Они появляются из-за расхождений написания разметки со стандартами W3C.
Тем не менее, предупреждения всё равно нужно устранять, так как из-за них сайт может работать медленнее — например, по сравнению с конкурентами с такими же сайтами.
Примером предупреждения может быть указание на отсутствие тега alt у изображения.
Ошибки
Ошибки — это те проблемы, которые требуют обязательного устранения.
Они представляют угрозу для корректной работы сайта: например, из-за них могут скрываться разные блоки — текстовые, фото, видео. А в некоторых более запущенных случаях содержимое страницы может вовсе не отображаться, и сам ресурс не будет загружаться. Поэтому после проверки уделять внимание ошибкам с красными отметками нужно в первую очередь.
Распространённым примером ошибки может быть отсутствие тега <!DOCTYPE html> в начале страницы, который помогает информации преобразоваться в разметку.
Пример прохождения валидации для страницы сайта
Рассмотрим процесс валидации на примере сайта avavax.ru, который создали на WordPress.
В результате проверки валидатор выдал 17 замечаний. После анализа отчета их можно свести к 3 основным:
- атрибут ‘text/javascript’ не требуется при подключении скрипта;
- атрибут ‘text/css’ не требуется при подключении стиля;
- у одного из элементов section нет внутри заголовка h1-h6.
Первое и второе замечания генерирует сам движок WordPress, поэтому разработчикам не нужно их убирать. Третье же замечание предполагает, что каждый блок текста должен иметь заголовок, даже если это не всегда необходимо или видно для читателя.
Решить проблемы с предупреждениями для стилей и скриптов можно через добавление кода в файл темы function.php.
Для этого на хук wp_loaded нужно повесить функцию output_buffer_start(), которая загрузит весь генерируемый код html в буфер. При выводе в буфер вызывается функция output_callback($tag), которая просматривает все теги, находит нежелательные атрибуты с помощью регулярных выражений и заменяет их пробелами. Затем на хук ‘shutdown вешается функция output_buffer_end(), которая возвращает обработанное содержимое буфера.
Для исправления семантики на сайте нужно использовать заголовки. Валидатор выдаёт предупреждение на секцию about, которая содержит фото и краткий текст. Валидатор требует, чтобы в каждой секции был заголовок. Для исправления предупреждения нужно добавить заголовок, но сделать это так, чтобы его не было видно пользователям:
- Добавить заголовок в код: <h3>Обо мне</h3>
Отключить отображение заголовка:
1 #about h3 {
2 display: none;
3 }
После этой части заголовок будет в коде, но валидатор его увидит, а посетитель — нет.
За 3 действия удалось убрать все предупреждения, чтобы качество кода устроило валидатор. Это подтверждается зелёной строкой с надписью: “Document checking completed. No errors or warnings to show”.
Как исправить ошибку валидации
Всё зависит от того, какими техническими знаниями обладает владелец ресурса. Он может сделать это сам, вручную. Делать это нужно постепенно, разбирая ошибку за ошибкой. Но нужно понимать, что если при проверке валидатором было выявлено 100 проблем — все 100 нужно обязательно решить.
Поэтому если навыков и знаний не хватает, лучше привлечь сторонних специалистов для улучшения качества разметки. Это могут быть как фрилансеры, так и профессиональные веб-агентства. При выборе хорошего специалиста, результат будет гарантироваться в любом случае, но лучше, чтобы в договоре оказания услуг будут чётко прописаны цели проведения аудита и гарантии решения проблем с сайтом.
Если объём работ большой, выгоднее заказать профессиональный аудит сайта. С его помощью можно обнаружить разные виды ошибок, улучшить внешний вид и привлекательность интернет-ресурса для поисковых ботов, обычных пользователей, а также повысить скорость загрузки страниц, сделать качественную верстку и избавиться от переспама.
Плагины для браузеров, которые помогут найти ошибки в коде
Для поиска ошибок валидации можно использовать и встроенные в браузеры плагины. Они помогут быстро находить неточности еще на этапе создания кода.
Для каждого браузера есть свой адаптивный плагин:
- HTML Validator для браузера Firefox;
- HTML Validator for Chrome;
- HTML5 Editor для Opera.
С помощью этих инструментов можно не допускать проблем, которые помешают нормальному запуску сайта. Плагины помогут оценить качество внешней и внутренней оптимизации, контента и другие характеристики.
Коротко о главном
Валидация — процесс выявления проблем с HTML-разметкой сайта и ее соответствия стандартам W3C. Это унифицированные правила, с помощью которых сайт может нормально работать и отображаться и для поисковых роботов, и для пользователей.
Проверку ресурса можно проводить тремя путями: валидаторами, специалистам полномасштабного аудита и плагинами в браузере. В большинстве случаев валидатор — самое удобное и быстрое решение для поиска проблем. С его помощью можно выявить 2 типа проблем с разметкой — предупреждения и ошибки.
Работать необходимо сразу с двумя типами ошибок. Даже если предупреждение не приведет к неисправности сайта, оставлять без внимания проблемные блоки нельзя, так как это снизит привлекательность ресурса в глазах пользователя. Ошибки же могут привести к невозможности отображения блоков на сайте, понижению сайта в поисковой выдаче или полному игнорированию ресурса со стороны поискового бота.
Даже у крупных сайтов с миллионной аудиторией, например, Яндекс.Дзен или ВКонтакте, есть проблемы с кодом. Но комплексный подход к решению проблем помогает устранять серьёзные моменты своевременно. Нужно развивать сайт всесторонне, чтобы получить результат от его существования и поддержки. Если самостоятельно разобраться с проблемами не получается, не стоит “доламывать” — лучше обратиться за помощью к профессионалам, например, агентствам по веб-аудиту.
сентябрь
17
, 2019
Когда мы создаем любые приложения, не стоит рассчитывать, что пользователи будут работать с ним так, как мы задумали. Нет, они постоянно будут делать тупые с нашей точки зрения вещи:
— добавлять товары с пустыми названиями
— прописывать цены строками
— копипастить портянки текста в описания, хотя мы четко написали в инструкции — не больше 200 символов.
Работать с нашим приложением будут не программисты. Представьте менеджера, которому нужно забить в базу 3 сотни товаров, и это до завтра.
Он не будет изучать нашу инструкцию, он сядет и сразу будет набивать по списку. Так сделает любой нормальный человек.
Наша задача, как программистов, сделать так, чтобы система обрабатывала любые данные.
Приложение должно или распарсить эти данные и понять, что хотел ввести пользователь, или приостановить работу и сказать, в чем ошибка.
И сказать человеческим языком, а не ошибкой в консоли. Сегодня мы займемся этой проблемой и посмотрим, как адекватно обрабатывать разные ошибки.
Валидация на клиенте и сервере. В чем разница?
Валидация на клиенте — это те ошибки, которые мы можем проверить средствами браузера. Например,
— юзер пытается добавить товар с пустым названием
— юзер забыл указать цену товара
— юзер вбивает длинное описание, хотя допускается максимум 200 символов.
Все это можно проверить в клиентской части приложения с помощью javascript.
Валидация на сервере — это все то, что можно проверить на клиенте, плюс некоторые специфичные вещи, часто связанные с базой. Например,
— юзер пытается добавить уже существующий товар
— юзер пытается удалить категорию, хотя в ней есть какие-то товары
— юзер пытается удалить бренд, но у него нет прав доступа на это
Все эти вещи проверяются на бекенде, клиент о них не знает.
Отмечу 2 момента:
— стоит по максимуму валидировать данные на клиенте
— дублировать эти же проверки на сервере.
Зачем это нужно?
Валидация на клиенте выполняется быстро и не требует лишнего запроса на сервер. Это ускоряет работу приложения.
Действительно, зачем юзеру ждать, пока запрос сбегает на сервер, если нужно всего лишь проверить, не пустое ли поле названия товара?
Дублировать эти же проверки на сервере нужно для других случаев. Во-первых, нашим приложением могут пользоваться по API, то есть не через интерфейс, а дергать rest-запросы напрямую.
И тут валидация на клиенте не поможет. А во-вторых, могут найтись какие-нибудь хакеры или бродящие по интернету боты, которые захотят поломать наш сервис, закинув в него неподходящие данные.
Вырисовывается простое правило: валидировать на клиенте нужно для нормальных людей, а дублировать те же проверки на сервере — для нехороших ботов и взломщиков.
Валидация в нашей админке интернет-магазина
До какой степени валидировать данные в приложении, каждый решает сам. Процесс этот бесконечный, можно проверять все, что угодно.
Главное, вовремя остановиться и не забыть проверить самые важные вещи.
В нашей админке мы не будем стелить соломку по всему коду, смысл уроков не в этом. Мы подробно рассмотрим валидацию только в одном компоненте, но покроем и клиентские, и серверные проверки.
И научимся показывать юзерам ошибки в человеческом виде.
Мы проработаем форму добавления брендов, которую сделали в прошлом уроке.
Сейчас мы можем добавить любой бренд, потому что никаких проверок нет. Исправим это и будем проверять такие вещи:
— не пустой ли бренд
— не превышает ли бренд 20 символов (практического смысла мало, но для примера нормально)
— существует ли этот бренд в базе
— нет ли ошибки в запросе (неверный роутер, проходили в третьем уроке)
— общие ошибки, например, сервис недоступен, бекенд лежит
Первые 2 проверки будем делать на клиенте, следующие 2 — на сервере. Пятая — это все невошедшие ошибки, например, упавший ajax-запрос или 500-ка от сервера.
Дублировать клиентские проверки на сервере мы не будем. Они очень простые и легко реализуются на php, не будем перегружать код.
Другие серверные ошибки, номер 3 и 4, уже реализованы в третьем уроке, когда мы готовили api для админки.
Общая схема обработки ошибок
Сделаем так. В окошке добавления бренда заведем поле, куда будем выводить сообщение об ошибке.
Пользователям все равно, клиентская это ошибка или серверная, для него это будет выглядеть одинаково, вот так
Чтобы понимать, какая именно ошибка произошла, добавим такое понятие — код ошибки. Например, на скриншоте код «brand_exists», что означает, бренд уже существует.
Это проверка серверная, но красное сообщение об этом не знает.
Код ошибки — единственное, на что будет ориентироваться это сообщение и все равно, откуда он придет, при клиентской валидации или с ответом от сервера.
Тексты сообщений мы будем брать из отдельного конфига. Теперь давайте сделаем это на практике.
Валидация на клиенте
Откроем компонент BrandsNew.vue и добавим новое поле errorCode, в раздел data. Это тот самый код, который определяет наличие ошибки. По умолчанию — пустая строка. То есть вот так
data () { return { visible: false, newBrand: '', // Новое поле errorCode: '' } }
Добавим еще вычисляемое логическое поле isError, которое покажет, если ли в данный момент ошибка
computed: { isError () { return this.errorCode !== ''; } }
Дальше нам нужно вывести сообщение об ошибки в окне добавления бренда. Добавим такой код между инпутом-брендом и кнопкой Добавить
Ошибка: {{errorCode}}
Это выделенный красным текст, пример взяли из библиотеки minicss. Напоминаю, наше приложение на этом css-фреймворке. Чуток поправим стили, добавим в style
mark { display: block; margin: 5px 0 10px 5px; }
Но вернемся к разметке. v-if=»isError» означает, что сообщение будем выводить только, когда есть ошибка, логично. А в тексте сообщения выведем пока код ошибки — {{errorCode}}.
Сначала убедимся, что наша схема работает, а потом заменим бездушный errorCode нормальным текстом.
Итак, errorCode у нас есть, нужны методы для работы с ним. Один метод будет устанавливать код, другой очищать. Добавим в раздел methods
setError (errorCode) { this.errorCode = errorCode; }, clearError () { this.errorCode = ''; }
Можно было обойтись и одним только setError, но позже увидим, что clearError удобная штука и нам еще пригодится.
Базовая подготовка сделана, пора заняться самой валидацией. Напомню, мы будем проверять, что новый бренд не пустой и что не длиннее 20 символов.
Метод валидации будет выполнять эти проверки и в случае ошибкок устанавливать соответствующий код codeError. Вот так выглядит метод validate
validate (brand) { if (brand === '') { this.setError('brand_empty'); return false; } if (brand.length > 20) { this.setError('brand_long_title'); return false; } // Если валидация прошла успешно this.clearError(); return true; }
Два простых if-а, которые проставляют нужные коды brand_empty или brand_long_title. А в случае успеха дергаем метод clearError, чтобы сбросить ошибку, если она была до этого.
Например, юзер ввел правильно инфу со второго раза.
Важный момент. Помимо установки codeError мы возвращаем true или false в зависимости от итога валидации.
Нам это нужно, чтобы понять, отправлять ли запрос на сервер с добавлением бренда или же ждать, пока юзер введет бренд правильно.
Посмотрим, какой метод добавления бренда мы написали раньше
addBrand () { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); }
Все просто, вызываем действие через dispatch, очищаем инпут с названием и закрываем модалку. Этот код нужно чуть переделать, вызывать действие только если валидация прошла успешно.
Добавим условие if
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); } }
На этом с клиентской валидацией все, можно проверять. Пробуем добавить пустой или чересчур длинный бренд, увидим сообщение с нужным кодом ошибки, а запрос на сервер не отправится.
Красота. Идем дальше.
Валидация на сервере
С серверными проверками есть свои особенности.
Во-первых, на клиенте мы генерили коды ошибок сами, а для серверных нужно дождаться ответа и получить их из респонса.
Да, мы эти коды (brand_exists и invalid_router) сами сделали в уроке по API. Но вообще мы можем даже и не знать, что за коды нам возвращает бекенд.
Во-вторых, есть интерфейсный момент. Сейчас в методе addBrand сразу после dispatch мы очищаем поле бренда и закрываем модалку.
Это годится, если бренд успешно добавлен и никуда не годится, если сервер вернул ошибку.
Значит, мы должны не просто дернуть dispatch, а дождаться ответа от сервера и только потом решать, что делать.
Если ответ 200 и бренд добавлен, то закрывать модалку, а если ошибка, то выводить ее и оставлять модалку.
Если бы мы писали приложение на jquery, то сделали бы примерно так
$.ajax({ url: '', data: '', success: function() { // очищаем поле бренда и закрываем модалку }, error: function() { // парсим код ошибки и выводим красное сообщение в модалке } });
Но мы уже серьезные ребята, у нас тут vue и вообще на хабре пишут, что ад из колбеков — это неправильно. Подключим промисы, здесь как раз тот случай, когда без них будет сложно.
Начнем с действия addBrand. Открываем файл store/modules/brands.js и смотрим, как реализовано сейчас
addBrand (context, newBrand) { const data = 'title=' + newBrand; axios .post('/admin/api/v1/brands', data) .then(response => { context.commit('ADD_BRAND', response.data) }); }
Отправляем запрос на сервер через axios и в случае успеха вызываем мутацию ADD_BRAND. Нам нужно сделать то же самое, только при этом еще и возвращать промис. Вот так
addBrand (context, newBrand) { const data = 'title=' + newBrand; return new Promise((resolve, reject) => { axios .post('/admin/api/v1/brands', data) .then(response => { context.commit('ADD_BRAND', response.data); resolve(response); }, error => { reject(error); }); }); }
Это стандартная заготовка для промисов. resolve и reject — это функции, которые выполняются соответственно при успехе и ошибке.
А что именно делают эти функции, будем решать уже в другом месте — опять в компоненте BrandsNew, в методе addBrand. Немного изменим код.
Было
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); } }
Стало
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand).then( response => { this.newBrand = ''; this.closeModal(); }, error => { let resp = error.response; let errorCode = (resp && resp.data && resp.data.code) ? resp.data.code : 'unknown_error'; this.setError(errorCode); }); } }
Кода прибавилось, но немного. В метод resolve попадает
response => { this.newBrand = ''; this.closeModal(); }
Параметр response нам не нужен, просто для наглядности. Получается, если запрос прошел успешно, бренд добавлен, то очищаем поле в модалке и саму модалку закрываем.
При ошибке выполняется другое
error => { let resp = error.response; let errorCode = (resp && resp.data && resp.data.code) ? resp.data.code : 'unknown_error'; this.setError(errorCode); });
Здесь параметр error уже нужен — это ответ от сервера, который нужно распарсить и вытащить код ошибки. Разберем по порядку. В первой строке пишем в переменную resp ответ от сервера.
Дальше идет диковатая конструкция resp && resp.data && resp.data.code. Зачем так сложно?
Ведь мы возвращаем ответ с бекенда в виде { code: ‘код ошибки’, … }, то есть поле code там будет всегда. Не совсем.
Код будет, но только для тех случаев, когда наш бекенд нормально обработает ошибку. Например, найдет, что бренд уже существует, или невалидный роутер (ошибка в запросе, в урле).
Если же бекенд просто лежит и вернет нам 500-ку, то в error.response может прийти null или пустая строка. Поэтому resp.data.code выкинет нам ошибку в консоль и поломает работу.
Поэтому именно здесь мы подстилаем соломку и проверяем всю цепочку error.response.data.code.
Только если data.code действительно существует, то мы понимаем, что эту ошибку вернул наш бекенд и в errorCode мы записываем валидное значение.
А в противном случае мы понимаем, что случилась какая-то хрень и поэтому ставим unknown_error. Типа «случилась непонятная хрень». Так и напишем пользователю.
Задача программиста как можно меньше пугать юзеров непонятными ошибками и стараться по максимуму обрабатывать их руками.
Другое дело, что пользователям вообще по фигу, лежит ли у вас бекенд, упала ли база и кто-то накосячил в коде. Ему важно, что приложение не работает и все.
Поэтому есть смысл не перегружать юзера техническими деталями, а выдать общую ошибку и попросить попробовать позже. Естественно, предполагается, что мы уже устраняем косяки и поднимаем бекенд.
Это все, что касается валидации на сервере. Можно проверять, попытаться добавить существующий бренд или изменить урл /admin/api/v1/brands на какой-нибудь левый.
Если все сделали правильно, то при добавлении бренда будет уходить запрос на сервер, возвращаться ошибка и модалка не закроется, а выведет код.
Когда мы будем тестировать работу, то заметим одну визуальную неприятность. Допустим, попытались мы добавить пустой бренд, нам выскочила ошибка brand_empty.
Изменяем бренд в инпуте, а ошибка так и торчит. Бесит. Давайте добавим одну строчку, чтобы при установке фокуса в инпуте ошибка пропадала. Теперь инпут будет выглядеть так
@focus=»clearError» — вот и пригодился метод clearError!
Вывод нормального сообщения об ошибке вместо кода
Коды ошибок у нас есть, осталось задать им адекватные тексты. Можно сделать это и в компоненте BrandsNew, но мы поступим интереснее.
Заведем в папке admin/vue/src папку configs, а в ней файлик brands.js. Давно было пора, потому что хорошее дело — выносить подобные вещи в конфиги, а не держать их в компонентах.
В файлике-конфиге напишем так
export default { errors: [{ code: 'brand_empty', message: 'Бренд не может быть пустым' }, { code: 'brand_long_title', message: 'Название не должно превышать 20 символов' }, { code: 'brand_exists', message: 'Бренд с таким названием уже существует' }, { code: 'invalid_router', message: 'Ошибка запроса. Попробуйте еще раз' }, { code: 'unknown_error', message: 'Неизвестная ошибка. Попробуйте позже' }] }
Просто массив из двух полей: код ошибки и текст сообщения. Можно было обойтись объектом, чтобы не бегать по массиву. Но на практике такие простые конфиги часто разрастаются.
То появится тултип с подробным описанием ошибки, то для каждой ошибки нужен будет свой цвет или еще какая-то фигня. Или вместо текстового кода мы решим использовать числовой.
В общем, чтобы не приходилось переделывать структуру конфига, сразу будем использовать массив объектов — в него добавлять новые поля безопасней.
Идем обратно в компонент BrandsNew. В теге script импортируем lodash и конфиг брендов
import _ from 'lodash'; import config from '../configs/brands';
Создаем новое вычисляемое поле в computed
errorMessage () { return this.errorCode !== '' ? _.find(config.errors, { code: this.errorCode }).message : ''; }
Это и есть сообщение об ошибке, которое берется из конфига по нужному коду. Осталось воткнуть его в разметку вместо errorCode. Вот так
{{errorMessage}}
Вот теперь все. У нас есть рабочая схема, по которой мы обрабатываем и клиентские, и серверные ошибки, используя один формат данных.
Теперь чтобы добавить новую проверку, достаточно будет воткнуть ее в метод validate, если проверка клиентская, и в php-шный код, если серверная.
Главное, вернуть с бекенда json формата { code: ‘код ошибки’, … }. И добавить новый объект в конфиг, чтобы показывать адекватные тексты пользователям.
До встречи в следующих уроках.
Все уроки админки на vue.js
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как правило, многие вебмастера загружают свои сайты на хост сразу-же после их создания. При этом они большей частью ориентируются на правильность составления смысла текстового содержания, чем на правильность внутреннего кода страниц.
Валидация сайта
Но есть и другие факторы, которые могут и влияют на позиции сайта. И к ним относятся, в том числе, и технические факторы. Ну а к техническим относятся и валидация сайта. Так что же это такое?
Если простыми словами, то валидация сайта — это проверка кода сайта на техническое соответствие и ошибки. Ну например, вы забыли использовать закрывающий тег — /html. В последнем HTML5, визуально ничего не поменяется. Однако, это ошибка кода.
При написании кода, возможны и другие ошибки. И опять-таки, современный язык гипер разметки «стерпит» многое. Например, «забытие» закрывающего тега /head. И снова вы не увидите разницу. Но она есть))
На самом деле, при написании сайта, ошибок может быть довольно много. И что хуже, некоторые из этих ошибок, могут проявиться и визуально. Ну может блоки поплывут, может выравнивание, а может и еще что-то. Потенциальных ошибок, тысячи. И далеко не все из них, бросаются в глаза.
В чем опасность?
Ну казалось-бы, ну и что тут такого? Да, нужно сказать, что зачастую такие ошибки не видимы. Точнее, невидимы человеком. А ведь страницы нашего сайта могут посетить не только люди, но и поисковые пауки, которые полностью просматривают сайт. И каждую ошибку, которую они находят на сайте, они передают на сервера поисковиков, таких как Яндекс или Гугл.
А поисковики, в свою очередь, видя что на сайте много ошибок кода, вполне могут сделать вывод о том, что сайт плохой. И значит, не будут поднимать его в поиске. Ну а это уже будет означать, что прощай посетители с поиска.
Да, надо признать, определенная пессимизация сайта из-за ошибок валидации, это довольно редкое явление. Но это вполне возможно, а значит, над валидацией обязательно нужно работать. А что для этого нужно сделать? Понятное дело, вначале ошибки нужно найти.
Но поскольку вручную это очень трудоёмкое и ненадежное дело, то для поиска ошибок, используются специальные сервисы, так называемые «Валидаторы».
Валидатор Markup Validation Service.
Этот сервис проверяет правильность кодов HTML и XHTML, которые являются основой большей части страниц при создании практически любого сайта и определяют его внутреннюю структуру. На этот сервис валидатора можно попасть, если пройти по ссылке http://validator.w3.org
Но здесь есть обязательное условие, которое также относится и к другим валидаторам: проверяемый сайт или его проверяемые страницы должны быть закачаны на хостинг. В противном случае, валидатор не будет «знать» адрес сайта и не сможет ничего проверить. Вот сейчас можно уже рассмотреть, как работать на этом валидаторе.
После захода на страницу этого сервиса, отобразиться вся его функциональная картинка. Но большая часть изображённого и написанного к основной проверке не относится и всё своё внимание надо обратить только на окно ввода адреса проверяемой страницы:
Вот именно с него и надо начинать.
Вообще-то, проверка валидации сайта чрезвычайно проста, как и весь наш бренный мир: в адресном окне сервиса надо написать адрес сайта, т.е. его URL и затем нажать «Check». После такого простого действия, валидатор «попыхтит» несколько секунд и выдаст следующее:
Это означает, что никаких ошибок в коде страницы нет и Вы можете быть абсолютно спокойны.
Но также может быть и такой нежелательный вариант:
Это уже похуже и означает, что во внутреннем коде проверяемой страницы есть какие-то ошибки. Однако, это совсем не смертельно: просто надо прокрутить страницу ниже и там подробно будут написаны все найденные ошибки в процессе проверки.
Кроме того, валидатор не только перечислит найденные ошибки, но и точно покажет, на какой строке внутреннего кода эти ошибки расположены. Так что долго их искать не придётся. Здесь, ничего не преувеличивая, можно твёрдо сказать, что этот валидор работает прекрасно.
Но это ещё не всё: валидатор не только указывает местоположение обнаруженной ошибки кода, но и даёт достаточно полные рекомендации, каким образом можно устранить эти ошибки. Конечно, для этого не надо лениться и внимательно прочитать всё написанное.
В качестве краткого и обобщенного вывода, можно сказать следующее:
- данный сервис валидатора работает прекрасно и может очень быстро провести проверку сайта.
- Ну и небольшое, но очень приятное дополнение: валидация сайта производиться бесплатно.
- Сейчас можно перейти к следующему этапу: это проверка кода CSS.
Валидатор CSS Validation Service
В общем это вторая функция вышеописанного сервиса, но она «заточена» не для проверки кода HTML и XHTML, а конкретно для проверки правильности кода стиля CSS, расположенного на внешней таблице. А чтобы попасть на страницу сервиса, надо пройти по ссылке http://jigsaw.w3.org/css-validator.
Кстати, здесь стоит отметить нечто приятное: проверка на этом сервисе абсолютно бесплатна. Так что не надо вытаскивать деньги из своего кошелька — пусть они лежат до нужного момента. Однако перейдём к методике работы на этом втором сервисе.
В общем-то вся работа на валидаторе CSS абсолютно идентична проверке на чистоту кода. Поэтому, приводить отдельную картинку адресной строки валидатора нет необходимости. Просто чуть ниже кратко рассмотрим непосредственно порядок самой проверки и всё.
Для этого надо в адресной строке записать URL таблицы CSS, типа «http://мой сайт/style.css» и после этого нажать кнопку с русской надписью «Проверить». Соответственно, этот валидатор тоже несколько секунд «попыхтит» и выдаст искомый результат:
Это значит, что таблица CSS написана правильно и никаких ошибок в ней не обнаружено.
И здесь также есть приятная неожиданность: если прокрутить страницу несколько ниже, то там будет написан оптимизированный код для Вашей таблицы CSS, из которого убраны все лишние надписи и все теги кода будут расставлены в той последовательности, которая соответствует оптимальным рабочим требованиям всех поисковых систем. Остаётся только скопировать этот идеальный образец кода и вставить его в таблицу CSS.
Вполне может быть, что случиться и такой вариант:
Это значит, что обнаружены какие-то ошибки в коде CSS, но пугаться этого совсем не стоит. Сразу внизу под этой красной строкой, валидатор точно укажет, какой тег написан неправильно. Остаётся только в таблице стиля найти эти теги и сделать нужные исправления.
И конечно, после этого закачать исправленную таблицу стиля на хост и при наличии зелёной строки можно с удовольствием скопировать оптимизированный код стиля таблицы CSS. Вполне понятно, что затем лучше всего поменять старый код на новый и оптимизированный.
Краткое резюме.
Выше были рассмотрены две самых основных и обязательных проверки валидации сайта. Без этих проверок даже не стоит открывать индексацию для поисковых систем в robots.txt В противном случае, сайт может быть проигнорирован для индексации поисковыми машинами и будет считаться неисправным с соответствующими санкциями.
Чтобы этого не произошло, надо затратить всего несколько минут, чтобы быть абсолютно спокойным и полностью уверенным в техническом состоянии своего сайта и всех его страниц. Конечно, необходимо ещё произвести дополнительные проверки ссылок и анкоров, видимости сайта на мобильных устройствах и параметры других кодов. Только тогда сайт можно считать готовым для его полного функционирования и для удачного и быстрого продвижению в ТОП.
Заранее хочется сказать, что все остальные проверки проходят также быстро и просто, как и рассмотренные выше — надо только внимательно прочитать порядок работы с валидатором.
Добавлено 19.04.2018г.
Распространенные ошибки валидности при проверке html кода
Решил дополнить статью ошибками HTML кода, которые часто встречаются на сайтах. Во всяком случае у меня их было много)). Сами ошибки валидатор подсвечивает желтым цветом.
1) Error: Character reference was not terminated by a semicolon.
Ошибка: символ не был прерван точкой с запятой — соответственно надо добавить.
2) Warning: Section lacks heading. Consider using h2-h6 elements to add identifying headings to all sections.
Предупреждение: Раздел не имеет заголовка. Рассмотрите возможность использования элементов h2-h6 для добавления идентифицирующих заголовков ко всем разделам. Тут все понятно, надо добавить хотя бы один подзаголовок. Это даже не ошибка, а рекомендация.
3) Error: Element noindex not allowed as child of element p in this context.
Ошибка: элемент noindex не разрешен как дочерний элемент элемента p в этом контексте. (Подавление дальнейших ошибок из этого поддерева.)
Решение простое, надо закомментировать тег ноиндекс, вид будет таким:
4) Error: The center element is obsolete.
Ошибка: тег «center» устарел — надо заменить, если речь про img то можно использовать атрибут align. Если что-то другое центрировали, то заменить на div.
5) An img element must have an alt attribute, except under certain
Ошибка: Элемент img должен иметь атрибут alt -тут все понятно, надо добавить атрибут альт, даже если он будет незаполненный, то ошибка уйдет.
6) The width attribute on the td element is obsolete. Use CSS instead.
Ошибка: Атрибут «width» на элементе «td» устарел
7) The type attribute is unnecessary for javascript resources
Ошибка: атрибут type не нужен для ресурсов javascript. Решение просто удаляем все лишнее и оставляем только тег «script».
The align attribute on the img element is obsolete.
Ошибка: Атрибут align для элемента img устарел. Сделайте выравнивание изображений дивами.
Ошибка: Неправильное использование тега «li»: отсутствует тег «ul», «ol» . Нужно проверить вложенность элементов списка.
10) End tag for «div» omitted, but OMITTAG NO was specified
Ошибка: Не хватает закрывающего тега div. Решение — добавляем элемент
11) End tag for element «div» which is not open
Ошибка: закрывающий тег div лишний. Соответственно удаляем.
Жду ваших комментариев, а у вас на сайтах валидный код?
Доброго времени, хаброчеловеки!
Мне хотелось бы поднять тему серверной валидации пользовательских данных. Поискав на хабре топики данной тематики и погуглив, пришёл к выводу, что люди часто изобретают свои собственные велосипеды для реализации механизма валидации. В данной статье хочу рассказать о простом и красивом решении, которое успешно применяется в нескольких проектах.
Проблема
Часто замечаю, что разработчики активно используют исключения (exceptions) для уведомления об ошибках валидации данных. Продемонстрирую примером (поскольку C# мне ближе, буду использовать его):
public void Validate(string userName, string userPassword)
{
if (/*проверяем имя пользователя*/)
throw new InvalidUsernameException();
if (/*проверяем пароль*/)
throw new InvalidPasswordException();
}
Далее это используется примерно так:
public void RegisterUser (string username, string password) {
try {
ValidateUser(username, password);
}catch(InvalidUsernameException ex) {
//добавляем в коллекцию ошибок
}catch(InvalidPasswordException ex) {
//добавляем в коллекцию ошибок
}//что-то дальше делаем
}
Что плохого в этом примере?
— используются исключения (exceptions) на этапе бизнес валидации. Важно помнить, что ошибки валидации данных != ошибкам работы приложения;
— использование исключений на этапе бизнес валидации может привести к падению приложения. Такое может произойти, например, если человек забудет написать ещё один блок catch для новых правил валидации;
— код выглядит некрасиво;
— подобное решение сложно тестировать и поддерживать.
Решение
Механизм валидации данных можно реализовать при помощи паттерна Composite (компоновщик).
Нам потребуется непосредственно сам объект валидатор, который непосредственно проверяет данные на соответствие определённым правилам, композитный валидатор, который инкаплусирует в себе коллекцию валидаторов, а также дополнительный класс, используемый в
качестве хранилища результата валидации и коллекции ошибок — ValidationResult. Рассмотрим вначале последний:
public class ValidationResult{
private bool isSucceedResult = true;
private readonly List<ResultCode> resultCodes = new List();protected ValidationResult() {
}public ValidationResult(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}public static ValidationResult SuccessResult {
get { return new ValidationResult(); }
}public List<ResultCode> GetResultCodes {
get { return resultCodes; }
}public bool IsSucceed {
get { return isSucceedResult; }
}public void AddError(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}public void Merge(ValidationResult result) {
resultCodes.AddRange(result.resultCodes);
isSucceedResult &= result.isSucceedResult;
}
}
Теперь перейдём непосредственно к механизму валидации. Нам необходимо создать базовый класс Validator, от которого будут наследоваться все валидаторы:
public abstract class Validator {
public abstract ValidationResult Validate();
}
У объектов-валидаторов существует 1 метод, который запускает процедуру проверки и возвращает результат.
CompositeValidator — класс, содержащий в себе коллекцию валидаторов и запускающий механизм проверки у всех дочерних объектов:
public class CompositeValidator : Validator {
private readonly List<Validator> validators = new List();public void Add(Validator validator) {
validators.Add(validator);
}public void Remove(Validator validator) {
validators.Remove(validator);
}public override ValidationResult Validate() {
ValidationResult result = ValidationResult.SuccessResult;
foreach (Validator validator in validators) {
result.Merge(validator.Validate());
}
return result;
}
}
Используя эти классы, мы получили возможность создавать валидаторы с определёнными правилами, комбинировать их и получать результаты проверки.
Использование
Перепишем приведённый в начале статьи пример с использованием этого механизма. В нашем случае необходимо создать 2 валидатора, которые проверяют имя пользователя и пароль на соответствие определённым правилам.
Создаём объект для проверки имени пользователя UserNameValidator:
public class UserNameValidator: Validator {
private readonly string userName;public UserNameValidator(string userName) {
this.userName= userName;
}public override ValidationResult Validate() {
if (/*параметр не прошёл проверку на условие, например userName = null*/) {
return new ValidationResult(ResultCode.UserNameIncorrect);
}return ValidationResult.SuccessResult;
}
}
Аналогично получаем UserPasswordValidator.
Теперь у нас есть всё, чтобы использовать новый механизм валидации данных:
public ValidationResult ValidateUser(string userName, string userPassword)
{
CompositeValidator validator = new CompositeValidator();
validator.add(new UserNameValidator(userName));
validator.add(new UserPasswordValidator(userPassword));return validator.Validate();
}public void RegisterUser (string username, string password) {
ValidationResult result = ValidateUser(username, password);if (result.IsSucceed) {
//успешная валидация
}else {
//получаем ошибки валидации result.GetResultCodes() и обрабатываем соответствующим образом
}
}
Выводы
Какие преимущества мы получили, используя данный подход:
— расширяемость. Добавление новых валидаторов стоит дешево;
— тестируемость. Все валидаторы могут быть модульно протестированы, что исключает наличие ошибок в общем процессе валидации;
— сопровождаемость. Валидаторы можно выделить в отдельную сборку и использовать во многих проектах с незначительными изменениями;
— красота и правильность. Данный код выглядит красивее, изящнее и правильнее, первоначального варианта, исключения не используются для бизнес валидации.
Заключение
В дальнейшем можно применить несколько улучшений к механизму валидации, а именно:
— инкапсулировать все валидаторы в одну сборку и создать фабрику, которая будет возвращать готовый механизм валидации для различных условий (проверка данных для регистрации пользователя, проверка данных при авторизации и т.д.);
— базовый класс Validator можно заменить на интерфейс, кому как нравится;
— правила валидации можно хранить в одном месте, для более удобного управления;
— можно написать обработчик ошибок валидации, который будет сопоставлять коды ошибок и сообщения, выводимые пользователям на UI, в таком случае ещё сильнее упрощается процесс добавления новых валидаторов. Также отпадает проблема локализации сообщений.
P.S.
Просьба сильно не пинать за возможные ошибки в написании и изложении. Я очень старался)
С удовольствием выслушаю критику и пожелания по поводу реализации и архитектуры.
* All source code was highlighted with Source Code Highlighter.
Валидация на стороне сервера
Валидация на стороне сервера должна осуществляться независимо от того, включена валидация на стороне клиента или нет. Пользователь может отключить JavaScript или совершить какие-нибудь другие непредвиденные действия, чтобы обойти валидацию на стороне клиента, и сервер останется последней линией защиты наших данных от некорректного ввода. Некоторые правила валидации требуют обработки данных на стороне сервера — топологией сети может быть установлено, что только сервер имеет доступ к внешним ресурсам, необходимым для проверки вводимых данных.
Мы рассмотрим два ключевых понятия. Сначала разберем самый распространенный способ валидации на стороне сервера с ASP.NET MVC, используя Data Annotations. Потом мы исследуем метаданные модели и научимся писать собственные реализации провайдеров метаданных.
Валидация с Data Annotations
Библиотека Data Annotations, впервые реализованная в пакете .NET 3.5 SP1, представляет собой набор атрибутов и классов, определенных в сборке System.ComponentModel.DataAnnotations
, которые позволяют добавить метаданные к классам. Метаданные описывают набор правил, с помощью которых можно определить, как проводить проверку конкретных объектов.
Кроме описания правил валидации, атрибуты DataAnnotations
используются для реализации новых шаблонных функций, как вы видели в главе 3 на примере атрибутов DisplayName
и DataType
. Специальные атрибуты для контроля валидации приведены в таблице 6-1.
ASP.NET MVC включает в себя набор классов резервной валидации для всех атрибутов, которые отвечают за выполнение текущей проверки данных. Изучим атрибуты валидации на примере интерфейса, которому необходима валидация. На рисунке 6-1 показана форма ввода Edit
с полями Company Name
и Email Address
.
Таблица 6-1: Атрибуты Data Annotations для валидации
Атрибут | Описание |
CompareAttribute |
Сравнивает значения двух свойств модели. Если они равны, валидация успешно завершена |
RemoteAttribute |
Указывает JQuery Validate, библиотеке валидации на стороне клиента, что она должна вызвать действие для валидации на сервере, и выводит ее результат до отправки формы |
RequiredAttribute |
Указывает, что требуется значение поля данных |
RangeAttribute |
Устанавливает ограничения числового диапазона для значения поля данных |
RegularExpressionAttribute |
Указывает, что значение поля данных должно соответствовать заданному регулярному выражению |
StringLengthAttribute |
Задает максимальное число символов, которые разрешены в поле данных |
Рисунок 6-1: Экран
Edit
с обязательным полем
В нашем приложении Company Name
– обязательное для заполнения поле, Email Address
— необязательное. Чтобы сделать поле Company Name
обязательным, мы используем RequiredAttribute
.
public class CompanyInput
{
[Required]
public string CompanyName { get; set; }
[DataType(DataType.EmailAddress)]
public string EmailAddress { get; set; }
}
Мы добавили RequiredAttribute
к свойству CompanyName
. Мы также добавили EmailAddress
к атрибуту DataTypeAttribute
, чтобы воспользоваться пользовательскими шаблонами для адресов электронной почты.
В нашем представлении нам нужно отображать потенциальные сообщения об ошибках валидации, и мы можем реализовать это несколькими способами. Мы можем использовать шаблоны, в которые уже включены сообщения валидации.
<h2>Edit</h2>
@using (Html.BeginForm("Edit", "Home")) {
@Html.EditorForModel()
<button type="submit">Submit</button>
}
Шаблоны редактирования модели, используемые по умолчанию, создают пользовательский интерфейс, который включает в себя как элементы ввода, так и сообщения проверки.
Для более детального управления выводом, мы можем использовать методы расширения валидации HtmlHelper
. Расширение ValidationSummary
предоставляет сводный список ошибок валидации, который обычно отображается в верхней части формы. Чтобы выводить ошибки валидации для конкретных свойств модели, мы можем использовать метод ValidationMessage
, а также ValidationMessageFor
, основанный на выражениях.
После вывода сообщения валидации мы должны убедиться, что наша модель действительна в результирующем методе контроллера метода POST
. Мы можем добавить к модели какие угодно атрибуты валидации, но управлять ошибками валидации все равно придется в методе контроллера.
[HttpPost]
public ActionResult Edit(CompanyInput input)
{
if (ModelState.IsValid)
{
return View("Success");
}
return View(new CompanyInput());
}
В действии Edit метода POST
мы сначала проверяем наличие ошибок в ModelState
. Движок валидации MVC помещает ошибки валидации в ModelState
, и их отсутствие отражается в свойстве IsValid
. Если ошибок нет, мы выводим экран с сообщением об успешном заполнении формы. В противном случае мы отображаем исходный экран Edit, теперь с сообщением об ошибке валидации.
Чтобы продемонстрировать ошибку валидации в этом примере, просто отправим форму, не заполняя поле для названия компании. На этой странице поле Company name
является обязательным. Результат показан на рисунке 6-2.
Рисунок 6-2: Ошибка валидации в результате отсутствия названия компании
Когда мы заполним форму, пропустив поле для названия компании, сообщение об ошибке валидации отображается корректно.
Тем не менее, на рисунке 6-2 показана проблема, связанная с сообщением об ошибке валидации и самим экраном. И сообщение об ошибке, и название поля отображаются как «CompanyName
» без пробела. Но мы хотим всегда включать пробелы между словами в названиях полей. Исправить название поля можно с помощью DisplayNameAttribute
(часть пространства имен System.ComponentModel
). Так как принято отображать имена свойств с пробелами между словами, мы расширим встроенный класс ModelMetadataProvider
с помощью метода, который будет автоматически добавлять пробелы.
Расширение ModelMetadataProvider
Как мы видели в предыдущей части, многие новые возможности в ASP.NET MVC используют метаданные модели. Шаблоны используют метаданные для отображения элементов ввода и текста, а провайдеры валидации используют метаданные для выполнения валидации.
Если мы хотим, чтобы метаданные для нашей модели извлекались из других источников, помимо Data Annotations, мы должны использовать ModelMetadataProvider
.
Листинг 6-1: Абстрактный класс
ModelMetadataProvider
public abstract class ModelMetadataProvider
{
public abstract IEnumerable<ModelMetadata> GetMetadataForProperties
(object container, Type containerType);
public abstract ModelMetadata GetMetadataForProperty
(Func<object> modelAccessor, Type containerType, string propertyName);
public abstract ModelMetadata GetMetadataForType
(Func<object> modelAccessor, Type modelType);
}
Класс ModelMetadataProvider
содержит методы, которые получают ModelMetadata
для каждого члена типа, для конкретно свойства и для частного типа, что показано в листинге 6.1.
Чтобы изменить отображаемый текст для конкретного свойства, нам нужно переопределить поведение базового класса DataAnnotationsModelMetadataProvider
. Класс AssociatedMetadataProvider
предоставляет общие функции для осуществления сценариев, в которых метаданные извлекаются из традиционных классов, свойств и атрибутов. Производным классам, таким как DataAnnotationsModelMetadataProvider
, нужно всего лишь создать ModelMetadata
уже уже существующих атрибутов.
В данном примере мы хотим изменить поведение DisplayName
в модели метаданных. По умолчанию свойство DisplayName
в ModelMetadata
приходит от DisplayNameAttribute
. Мы все еще хотим поддерживать значение DisplayName
через атрибут.
В листинге 6-2 мы расширяем встроенный класс DataAnnotationsModelMetadataProvider
создавая DisplayName
из имени свойства, разделяя его пробелами.
Листинг 6-2: Пользовательский провайдер метаданных
public class ConventionProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
var meta = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (meta.DisplayName == null)
meta.DisplayName = meta.PropertyName.ToSeparatedWords();
return meta;
}
}
Строка 3: Переопределяет
CreateMetadata
Строка 10: Вызывает базовый метод
Строка 12: Разделяет слова в имени свойства пробелами
Чтобы создать соответствующую схему соглашения для отображения имен, мы создаем класс, который наследуется от класса DataAnnotationsModelMetadataProvider
. Этот класс имеет довольно много встроенных возможностей, так что нам остается только переопределить метод CreateMetadata
(строка 3). Базовый класс содержит поведение, которые мы хотим сохранить, поэтому мы сначала вызываем метод базового класса (строка 10) и сохраняем его результаты в локальной переменной. Так как мы могли поместить значение атрибута в DisplayName
, теперь мы хотим изменить сценарий только в том случае, если значение DisplayName
еще не было установлен. Итак, если оно не было установлено, мы хотим разделить имя свойства на отдельные слова с помощью расширенного метода ToSeparatedWords
(строка 12). Наконец, мы возвращаем объект ModelMetadata
, содержащий измененное имя.
Метод расширения ToSeparatedWords
— довольно простое регулярное выражение для разделения идентификаторов на отдельные слова.
public static class StringExtensions
{
public static string ToSeparatedWords(this string value)
{
if (value != null)
return Regex.Replace(value, "([A-Z][a-z]?)", " $1").Trim();
return value;
}
}
Когда мы создали пользовательский ModelMetadataProvider
, мы должны настроить ASP.NET MVC, чтобы его использовать. Такая настройка проводится в файле Global.asax
:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new ConventionProvider();
}
Чтобы переопределить провайдер метаданных, мы записываем новый провайдер в свойстве ModelMetadataProviders.Current
. Когда настройка проведена, сообщения валидации и названия полей отображаются корректно, как показано на рисунке 6.3.
Рисунок 6-3: Экран Edit с корректно отображающимися названиями полей и сообщением об ошибке.
Используя соответствующую соглашению модификацию DataAnnotationsModelMetadataProvider
, мы можем использовать имена свойств в названиях полей и сообщениях об ошибках. В противном случае мы должны были бы избегать шаблонов редактирования и отображения, или записывать отображаемые имена в атрибутах.
В приведенных примерах до сих пор мы использовали исключительно валидацию на стороне сервера, но ASP.NET MVC включает поддержку двойной валидации и на стороне сервера, и на стороне клиента, которую мы рассмотрим в следующем разделе.
Всем привет, я Кирилл, СТО Adapty. Я делал систему серверной валидации для наших SDK и сегодня расскажу про то, как её настроить для приложений на Android.
Это пятая статья из серии о внедрении внутренних покупок на Android, советую познакомиться с остальными:
-
Android in-app purchases, часть 1: конфигурация и добавление в проект.
-
Android in-app purchases, часть 2: инициализация и обработка покупок.
-
Android in-app purchases, часть 3: получение активных покупок и смена подписки.
-
Android in-app purchases, часть 4: коды ошибок от Billing Library и как не облажаться с тестированием.
-
Android in-app purchases, часть 5: серверная валидация покупок. — Вы тут.
Что такое серверная валидация покупки?
Серверная валидация позволяет проверить подлинность покупки: устройство обращается к серверам Google за информацией, действительно ли была совершена покупка, и валидна ли она.
Зачем валидировать покупки
Серверная валидация необязательна, покупки будут работать без неё. Но с ней лучше, потому что она даёт важные преимущества:
-
Продвинутая аналитика платежей. Это особенно актуально для подписок. После того, как подписка активирована, списания происходят без участия устройства. Если пользователь не заходит в приложение, без серверной обработки мы не сможем своевременно получать информацию о статусе подписки: продлил, отменил, возникла проблема с платежом.
-
Проверка подлинности покупки. Серверная валидация позволяет убедиться, что транзакция действительно произошла, и покупка была не фродовой. Поскольку на Android процент мошеннических операций выше, чем на iOS, то в приложениях на Google Play об этом особенно важно позаботиться.
-
Кроссплатформенные подписки, имея данные по статусу подписки в живом режиме, можно синхронизировать подписки пользователя с другими платформами. Так, если пользователь подписался на приложение на Android, доступ к нему у него будет на iOS, Web и других платформах.
-
Возможность контролировать доступ к контенту со стороны сервера. Серверная валидация не даст доступ к контенту тем пользователям, которые хотят получить его, отправляя запросы к серверу.
Вообще уже один первый пункт стоит того, чтобы настроить серверную валидацию.
Валидация платежей
В целом процесс валидации платежей на Android можно описать схемой:
Аутентификация запросов к Google Play Developer API
Для того, чтобы работать с Google Play Developer API, необходимо создать ключ, с помощью которого будут подписываться все запросы. Сначала надо связать аккаунт Google Play Console (место, где вы управляете приложением) с аккаунтом в Google Cloud (там будет создавать ключ для подписи запросов). После того, как всё настроено, необходимо дать права пользователю на менеджмент покупок. Чтобы подробно описать весь этот процесс, понадобится отдельная статья. К счастью, мы уже сделали пошаговую инструкцию в документации Adapty, а к выходу этой статьи я обновил скриншоты, потому что интерфейс периодически меняется.
Обратите внимание, что обычно после создания ключа необходимо ждать сутки или больше, прежде чем он заработает. Чтобы этого не делать, можно обновить описание у любого in-app продукта или подписки, тогда ключ сразу будет активным.
Мы используем официальную библиотеку google-api-python-client для работы с Google Play Developer API. Данная библиотека доступна для большинства популярных языков, и я рекомендую использовать её, потому что в ней поддерживаются все нужные методы.
Валидация транзакций о подписке
В отличии от серверной валидации iOS, в Android валидация подписок и остальных продуктов делается с помощью разных методов. Поэтому в момент валидации вам необходимо понимать, работаете ли вы с подпиской или продуктом. На практике это означает, что вам надо передавать эту информацию со стороны мобильного приложения, а также хранить флаг в базе данных, если возникнет необходимость повторной проверки токена.
Второе большое отличие — в Android у каждой транзакции есть свой токен, в то время как на iOS все транзакции хранятся в одном токене (shared secret). Это означает, что для восстановления покупок пользователя необходимо хранить все токены покупок, а не только один для любой из них.
Для валидации подписки необходимо вызвать метод purchases.subscriptions.get. По факту это вызов GET-запроса https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}
.
Все параметры обязательны:
-
packageName
— идентификатор приложения, например, com.adapty.sample_app. -
subscriptionId
— идентификатор подписки, которую нужно провалидировать, например, com.adapty.sample_app.weekly_sub. -
token
— уникальный токен транзакции, который появляется после покупки на стороне мобильного приложения.
Для начала разберём ошибки, которые необходимо отслеживать, чтобы всё корректно работало:
-
400, Invalid grant: account not found — ошибка означает, что неправильно создан ключ для аутентификации запросов. Убедитесь, что используется верный аккаунт, учётные записи связаны, есть достаточные права, а также активированы необходимые API. О том, как всё правильно настроить, написано в предыдущей секции. Также обратите внимание на подсказку про обновление описания продукта.
-
400, The purchase token does not match the package name — эта ошибка чаще всего встречается во фродовых транзакциях. Если вы видите её в процессе тестирования, убедитесь, что вы не отправляете токен от покупки в одном приложении в другое.
-
403, Quota exceeded for quota metric ‘Queries’ and limit ‘Queries per day’ of service ‘androidpublisher.googleapis.com’ — превышена квота на количество запросов к API Google в сутки. По умолчанию можно отправлять не более 200000 запросов в сутки. Эту квоту можно увеличить, но для большинства приложений её должно быть достаточно. Возможно, если вы упёрлись в неё, то стоит убедиться в правильности логики работы.
-
410, The subscription purchase is no longer available for query because it has been expired for too long — ошибка возвращается для транзакций, где подписка истекла более 60 дней назад. По сути это не ошибка, так что не стоит её обрабатывать как ошибку.
Подписочная транзакция
В случае успешной валидации в ответ приходит информация о транзакции.
Информация о транзакции (подписка)
{
"expiryTimeMillis": "1631116261362",
"paymentState": 1,
"acknowledgementState": 1,
"kind": "androidpublisher#subscriptionPurchase",
"orderId": "GPA.3382-9215-9042-70164",
"startTimeMillis": "1630504367892",
"autoRenewing": true,
"priceCurrencyCode": "USD",
"priceAmountMicros": "1990000",
"countryCode": "US",
"developerPayload": ""
}
Чтобы понимать, есть ли у пользователя доступ к платным функциям приложения, то есть имеется ли у него активная подписка, необходимо:
-
Проверить параметры
startTimeMillis
иexpiryTimeMillis
, текущее время должно быть между ними. -
Кроме того, необходимо убедиться, что параметр
paymentState
не равен1
. Это означает, что подписка ожидает оплаты и в настоящий момент не нужно давать доступ к платным функциям приложения. -
Если в транзакции присутствует поле
autoResumeTimeMillis
, то подписка на паузе, то есть доступ к платным функциям приложения не нужно предоставлять раньше этой даты.
Давайте разберём важные свойства подписочной транзакции:
-
kind
— тип транзакции, у подписок он всегдаandroidpublisher#subscriptionPurchase
. С помощью этого параметра можно определять, подписка перед вами или продукт, и в зависимости от этого выбирать логику обработки. -
paymentState
— статус платежа, не приходит для истёкших транзакций. Возможные значения:-
0
— по данной транзакции ещё не прошла оплата. В некоторых странах подписку можно оплатить в магазине, то есть сначала пользователь оформляет её на устройстве, потом идёт в терминал и оплачивает там. В целом, это редкий кейс, но стоит иметь в виду. -
1
— подписка оплачена. -
2
— подписка находится в триальном периоде. -
3
— в следующем периоде произойдёт апгрейд или даунгрейд текущей подписки, то есть смена тарифного плана.
-
-
acknowledgementState
— статус подтверждения покупки. Это важный параметр, который служит для подтверждения, получил ли пользователь доступ к тому, за что он платил. Значение0
означает, что не получил,1
— получил. Разработчик сам отвечает за простановку этого статуса, это можно сделать как на стороне мобильного приложения, так и на стороне сервера. Если не подтвердить статус покупки, то через 3 дня автоматически произойдёт рефанд. Рекомендую реализовать логику, что, если в транзакции пришёлacknowledgementState=0
, то сервер его изменяет. О том, как это сделать, расскажу ниже. -
orderId
— уникальный идентификатор транзакции. У каждой покупки/продления будет свой идентификатор, его можно использовать, чтобы понимать, была ли ранее обработана данная транзакция. У каждого продления основная часть идентификатора остаётся неизменной, просто в конце добавляется две точки и номер продления, начиная с 0. Если при активации подписки у неё был идентификаторGPA.3382-9215-9042-70164,
то у первого продления будетGPA.3382-9215-9042-70164..0
, у второго —GPA.3382-9215-9042-70164..1
и тд. Таким образом можно выстраивать цепочки транзакций и отслеживать количество продлений. -
startTimeMillis
— дата начала подписки. -
expiryTimeMillis
— дата окончания подписки. -
autoRenewing
— флаг, показывающий, будет ли продлена подписка на следующий период. -
priceCurrencyCode
— валюта покупки в 3-х символьном формате, например RUB. -
priceAmountMicros
— цена покупки. Для того, чтобы получить нормальное числовое значение цены, надо поделить данное значение на 1000000. То есть 1990000 — это 1.99. -
countryCode
— страна аккаунта, с которого совершена покупка, в 2-х символьном формате, например, RU. -
purchaseType
— тип покупки. В большинстве случаев этого ключа нет. Но при этом его важно учитывать, потому что с помощью него можно понимать, что покупка была совершена в Sandbox окружении. Возможные значения:-
0
— покупка из Sandbox окружения, то есть её не нужно учитывать в аналитике. -
1
— покупка оплачена промокодом.
-
-
autoResumeTimeMillis
— дата, когда подписка возобновится. Приходит только для подписок, которые были поставлены на паузу. Если этот параметр есть, то доступ к платным функциям приложения не нужно предоставлять раньше указанной даты. -
cancelReason
— причина, по которой подписка не будет продлеваться на следующий период. Возможные значения:-
0
— пользователь сам отменил автопродление. -
1
— подписка отменена системой, чаще всего это связано с billing issue, то есть с пользователя не смогли снять деньги. -
2
— пользователь перешёл на другую подписку. -
3
— разработчик отменил подписку.
-
-
userCancellationTimeMillis
— дата, когда пользователь отменил продление подписки. Приходит только еслиcancelReason=0
. Подписка может быть всё ещё активна, это надо смотреть по параметруexpiryTimeMillis
. -
cancelSurveyResult
— объект, в котором хранится информация о причине отмены подписки пользователем, если он ответил на данный вопрос. -
introductoryPriceInfo
— объект, в котором хранится информации о цене для вводного периода (специальное предложение, например 1 месяц со скидкой 50%). -
promotionType
— тип промокода, который был использован при активации подписки. Возможные значения:-
0
— одноразовый промокод. -
1
— кастомный промокод, который может быть использован несколькими пользователями. Такие коды можно использовать для рекламы у блогеров.
-
-
promotionCode
— кастомный промокод, который был использован при активации подписки. Данный параметр не приходит для одноразовых промокодов. -
priceChange
— объект, в котором хранится информация о будущем изменении цены, а также статус того, одобрил ли пользователь это изменение или нет.
Подтверждение подписки (acknowledge subscription)
Как говорилось выше, если не подтвердить подписку, то через 3 дня она будет автоматически отменена, и пользователю вернутся деньги. Если честно, я не понимаю, зачем нужна такая логика, ни в каких других системах оплаты, в том числе iOS, я её не встречал. Тем не менее, если в транзакции пришёл acknowledgementState=0
, необходимо подтвердить подписку.
Чтобы подтвердить подписку, нужно вызвать метод purchases.subscriptions.acknowledge. Данный метод делает POST-запрос https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:acknowledge
. Параметры точно такие же, как при валидации запроса. В случае успешного выполнения запроса подписка будет подтверждена, а значит, вы не потеряете деньги.
Если подписка ещё не оплачена, то её не надо подтверждать.
Отмена возобновления, отзыв, рефанд и продление подписки
Кроме валидации и подтверждения подписки, с помощью Google Play Developer API можно делать ещё несколько операций с подписками. Стоит отметить, что все они довольно редкие, и за исключением продления, все поддерживаются в Google Play Console. Но всё же перечислю их, чтобы было общее представление о возможностях API. Во всех запросах такие же обязательные параметры, как и в ранее рассмотренных методах: packageName
, subscriptionId
и token
.
-
Отмена возобновления. Метод purchases.subscriptions.cancel. Отменяет продление для выбранной подписки, при этом подписка будет активна до окончания текущего периода.
-
Рефанд (возврат денег) подписки. Метод purchases.subscriptions.refund. Возвращает пользователю деньги за подписку. При этом доступ к подписке остаётся, и в следующем периоде она автоматически продлится. В большинстве случаев вместе с рефандом надо использовать отзыв подписки.
-
Отзыв подписки. Метод purchases.subscriptions.revoke. Моментально прекращает действие подписки, то есть у пользователя сразу же пропадает доступ к платным функциям приложения. Подписка не будет продлеваться в дальнейшем. Обычно используется вместе с рефандом.
-
Продление подписки. Метод purchases.subscriptions.defer. Продлевает действие подписки до указанной даты. В запросе необходимо передать текущую дату истечения подписки и желаемую, которая обязательно больше текущей.
Валидация продуктов (не подписок)
Валидация продуктов похожа на валидацию подписок. Необходимо вызвать метод purchases.products.get, который выполнит GET-запрос https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}
. Все параметры уже нам знакомы из рассмотренных ранее примеров.
Информация о транзакции (продукт)
{
"purchaseTimeMillis": "1630529397125",
"purchaseState": 0,
"consumptionState": 0,
"developerPayload": "",
"orderId": "GPA.3374-2691-3583-90384",
"acknowledgementState": 1,
"kind": "androidpublisher#productPurchase",
"regionCode": "RU"
}
Транзакция продукта содержит заметно меньше значений, чем транзакция подписки. Рассмотрим важные свойства:
-
kind
— тип транзакции, у продуктов он всегда androidpublisher#productPurchase. С помощью этого параметра можно определять, подписка перед вами или продукт, и в зависимости от этого выбирать логику обработки. -
purchaseState
— статус платежа. Обратите внимание, что значения ключей тут отличаются от параметра paymentState в подписке. Возможные значения:-
0
— покупка оплачена. -
1
— покупка отменена, то есть она ожидала оплаты, но в итоге пользователь её не оплатил. -
2
— покупка ожидает оплаты. В некоторых странах покупку можно оплатить в магазине, то есть сначала пользователь делает покупку на устройстве, потом идёт в терминал и оплачивает там. В целом, это редкий кейс, но стоит иметь в виду.
-
-
acknowledgementState
— статус подтверждения покупки. Как и в транзакциях подписки, этот параметр нужен для подтверждения, получил ли пользователь доступ оплаченным функциям/коненту. Значение0
означает, что не получил,1
— получил. За простановку этого статуса отвечает разработчик, сделать это можно и на стороне мобильного приложения, и на стороне сервера. Если не подтвердить статус покупки, то через 3 дня автоматически произойдёт рефанд. Рекомендую реализовать логику, что если в транзакции пришёлacknowledgementState=0
, то сервер его изменяет. Ниже расскажу, как это делается. -
consumptionState
— статус потребления продукта. Это то, что в iOS называется consumable. Задаётся со стороны мобильного приложения Значение0
означает, что продукт не употреблён, а1
— употреблён. Если вы продаёте доступ к приложению навсегда или доступ к определённой функциональности приложения навсегда, то такой продукт не нужно употреблять, то есть статус должен быть0
. Если же вы продаёте монетки, и пользователь может покупать их много раз, то такие продукт нужно употреблять, то есть статус должен быть1
.consumptionState=0
означает, что продукт можно купить только один раз, аconsumptionState=1
— много раз. -
orderId
— уникальный идентификатор транзакции. У каждой покупки будет свой идентификатор, его можно использовать, чтобы понимать, была ли ранее обработана данная транзакция. -
purchaseTimeMillis
— дата покупки. -
regionCode
— страна аккаунта, с которого совершена покупка в двухсимвольном формате, например, RU. Обратите внимание, что название этого параметра отличается от подписки, там он называется countryCode. -
purchaseType
— тип покупки. В большинстве случаев этого ключа нет. Но при этом его важно учитывать, потому что с помощью него можно понимать, что покупка была совершена в Sandbox окружении. Возможные значения:-
0
— покупка из Sandbox окружения, то есть её не нужно учитывать в аналитике. -
1
— покупка оплачена промокодом. -
2
— покупка выдана за целевое действие, например, пользователь смотрел рекламу вместо оплаты.
-
Как видите, в целом валидация продукта похожа на валидацию подписки, но есть странные моменты:
-
Не возвращается цена, хотя это очень удобно для аналитики.
-
В параметре
purchaseState
значения сильно отличаются от значенийpaymentState
в подписке, если это не учитывать, то будут ошибки. -
Возвращается
regionCode
, хотя в подписке он называетсяcountryCode
.
Покупку продуктов надо подтверждать, так же как и покупку подписки. Для этого необходимо вызвать метод purchases.products.acknowledge, который сделает POST-запрос https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}:acknowledge
.
Если покупка ещё не оплачена, то её не надо подтверждать.
Отслеживание рефандов (возвратов денег) подписок и продуктов
Для качественной аналитики вам необходимо учитывать рефанды. К сожалению, информация о рефанде не приходит внутри транзакции или отдельным событием, как это работает в iOS. Для получения списка транзакций, по которым вернули деньги, надо с определённой периодичностью (например, раз в сутки) вызывать метод purchases.voidedpurchases.list, который выполняет GET-запрос https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/voidedpurchases
. В ответ вернётся список всех транзакций, по которым произошёл возврат денег. Рекомендую использовать для поиска транзакций в базе параметр orderId
, а не purchaseToken
. Во-первых, так будет быстрее, а во-вторых, у всех продлений подписки будет один и тот же токен, и вам надо находить последний из них.
Серверные уведомления о транзакциях
Серверные уведомления (Real-time developer notifications) позволяют получать информацию о событии, которое произошло на стороне Google, на вашем сервере практически моментально. После их настройки вы будете получать информацию о новых покупках, продлениях, проблемах с платежами и так далее. Это позволяет собирать более точную аналитику, а также упрощает менеджмент состояния подписчика.
Для того, чтобы получать серверные уведомления, необходимо в Google Cloud Pub/Sub создать топик, который будет отправлять уведомления по желаемому адресу. После этого данный топик необходимо указать в разделе Monetization setup в Google Play Console. Подробнее об этом со скриншотами вы можете прочитать в документации Adapty.
Серверное уведомление
{
"message": {
"data": "eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20uYWRhcHR5LnNhbXBsZV9hcHAiLCJldmVudFRpbWVNaWxsaXMiOiIxNjMwNTI5Mzk3MTI1Iiwic3Vic2NyaXB0aW9uTm90aWZpY2F0aW9uIjp7InZlcnNpb24iOiIxLjAiLCJub3RpZmljYXRpb25UeXBlIjo2LCJwdXJjaGFzZVRva2VuIjoiY2o3anAuQU8tSjFPelIxMjMiLCJzdWJzY3JpcHRpb25JZCI6ImNvbS5hZGFwdHkuc2FtcGxlX2FwcC53ZWVrbHlfc3ViIn19",
"messageId": "2829603729517390",
"message_id": "2829603729517390",
"publishTime": "2021-09-01T20:49:59.124Z",
"publish_time": "2021-08-04T20:49:59.124Z"
},
"subscription": "projects/935083/subscriptions/adapty-rtdn"
}
Нас в первую очередь интересует ключ data
, в котором лежит информация о транзакции, закодированная с помощью base64. Ключ messageId
можно использовать для дедупликации сообщений, чтобы не обрабатывать повторно пришедшие сообщения.
Транзакция в серверном уведомлении
{
"version": "1.0",
"packageName": "com.adapty.sample_app",
"eventTimeMillis": "1630529397125",
"subscriptionNotification": {
"version": "1.0",
"notificationType": 6,
"purchaseToken": "cj7jp.AO-J1OzR123",
"subscriptionId": "com.adapty.sample_app.weekly_sub"
}
}
С помощью ключа packageName
можно понять, к какому приложению относится событие. Ключ subscriptionId
говорит, о какой подписке идёт речь, а с помощью purchaseToken
мы можем найти конкретную транзакцию. В случае с подписками надо всегда искать последнюю транзакцию в цепочке продления, событие относится именно к ней. В ключе notificationType
указан тип события. На мой взгляд, самые полезные для подписок:
-
2: SUBSCRIPTION_RENEWED
— подписка успешно продлилась. -
3: SUBSCRIPTION_CANCELED
— пользователь выключил автопродление подписки. Если автопродление выключили, надо пытаться вернуть пользователя в число активных подписчиков. -
5: SUBSCRIPTION_ON_HOLD
,6: SUBSCRIPTION_IN_GRACE_PERIOD
— подписку не получилось продлить из-за проблем с оплатой. Стоит сообщить пользователю об этом, чтобы у него не отменилась подписка автоматически. -
12: SUBSCRIPTION_REVOKED
— подписка отозвана. Нужно закрыть пользователю доступ к функциям, которые давала эта покупка.
Для продуктов (не подписок) вместо ключа subscriptionNotification
будет приходить oneTimeProductNotification
, и в нём вместо ключа subscriptionId
будет sku
. Также для продуктов приходит всего 2 типа события:
-
1: ONE_TIME_PRODUCT_PURCHASED
— успешная покупка продукта. -
2: ONE_TIME_PRODUCT_CANCELED
— покупка продукта отменилась, потому что пользователь не оплатил его.
Заключение
Серверная валидация сильно снижает возможность несанкционированного доступа к платному контенту вашего приложения и улучшает качество аналитики. При настройке серверной валидации придётся учитывать много сайд-кейсов: upgrade подписки, смена подписки, триал, introductory price, возвраты. Кроме того, есть ещё нюансы, вроде того, что Google снижает комиссию с 30% до 15% для подписок, которые продлеваются больше года. Так что весь процесс долгий и трудоёмкий.
Если хотите сэкономить ресурсы своей команды разработчиков, то советую присмотреться к Adapty.
Про Adapty
Adapty не только упрощает техническую реализацию подписок:
-
Встроенная аналитика позволяет быстро понять основные метрики приложения.
-
Когортный анализ отвечает на вопрос, как быстро сходится экономика.
-
А/Б тесты увеличивают выручку приложения.
-
Интеграции с внешними системами позволяют отправлять транзакции в сервисы атрибуции и продуктовой аналитики.
-
Промо кампании уменьшают отток аудитории.
-
Open source SDK позволяет интегрировать подписки в приложение за несколько часов.
-
Серверная валидация и API для работы с другими платформами.
Познакомьтесь подробнее с этими возможностями, чтобы быстрее внедрить подписки в своё приложение и улучшить конверсии.
Написал(а):
robot
8 лет,2 месяцев назад
http://habrahabr.ru/post/243637/
Думаю, для многих из нас фраза «валидация форм» является синонимом кучи дополнительного проверочного кода в контроллерах, длительной настройки всевозможных плагинов валидации, и так далее. Да, современный мир предлагает множество самых разных решений этой проблемы, как на клиентской стороне, так и на серверной. Но если честно, говоря о клиентской валидации… какие-то все эти библиотеки слишком громоздкие и неповоротливые, настолько, что у меня каждый раз отбивало желание подключать их к своим проектам. Да и на стороне сервера хотелось бы запрятать проверку введённых данных куда-нибудь в сторону от основной логики работы приложения.
Поэтому я и решил в конце-концов собрать весь код, который я писал в проектах, и скомпоновать его в одну небольшую библиотеку под названием PrettyForms. Библиотека эта содержит совсем немного кода, но при этом задачу свою она уже сейчас неплохо решает.
Зависимости: jQuery.
Пример работы:
PrettyForms изначально заточена под сайты, созданные на основе Twitter Bootstrap, но вы легко можете заменить её шаблоны с собщениями об ошибках на свои собственные, переопределив три переменных в объекте «PrettyForms.templates».
Весь исходный код достаточно подробно прокомментирован, так как мной предполагается, что другие люди захотят изменить логику работы каких-то частей библиотеки и доработать её под свои личные нужды, так как из коробки она имеет довольно скромный и минималистичный функционал, который был необходим лично мне для работы моих проектов.
Самый простой вариант
Чтобы она просто начала работать, необходимо лишь подключить её к странице, а после этого добавить для всех полей, для которых необходима валидация, атрибут «data-validation», содержащий правила валидации, описанные на странице библиотеки в разделе «Валидаторы полей».
Всё. Больше ничего делать не надо, всё остальное библиотека сделает за вас К этому я и стремился изначально: как можно меньше телодвижений.
Это самый простой вариант, без учёта серверной валидации данных. Если же у вас появилось желание использовать все возможности PrettyForms, тогда вам следует изучить алгоритм работы и протокол общения клиентской машины с сервером, благодаря которому она и становится столь удобной в использовании.
Вариант с клиент-серверной валидацией
Алгоритм работы:
- Пользователь заполняет поля и нажимает кнопку отправки формы. Библиотека проводит валидацию всех данных, и если всё нормально, она собирает все данные формы, отправляет POST-запрос на сервер и ожидает от него JSON-ответ в специальном формате.
- Сервер, получив запрос, проводит дополнительную валидацию данных уже на своей стороне. Если возникли ошибки при серверной валидации, он возвращает клиенту специальным образом сформированный JSON-ответ, содержащий команду для отображения ошибок серверной валидации с информацией о полях и содержащихся в них ошибках.
- Если данные успешно прошли валидацию и на сервере, сервер производит необходимые операции и возвращает JSON-ответ с командами, описывающими действия, которые клиентская машина должна выполнить после успешного выполнения операции.
То есть, сервер всегда отвечает определённым набором команд для браузера, а браузер просто исполняет данные команды на клиенской машине. Таков алгоритм работы библиотеки. Более подробное описание протокола можно найти на странице библиотеки в разделе «Формат протокола общения клиента с сервером».
Для того чтобы настроить библиотеку для работы с сервером, добавьте к вашей стандартной кнопке отправки формы класс senddata, благодаря которому клики по кнопке будут перехвачены и обработаны библиотекой. Также ей следует добавить два новых атрибута:
- data-input=»<jquery-селектор формы, из которой будут собраны данные>»
- data-link=»<url, на который будут отправлены данные>»
Теперь библиотека не только будет производить клиентскую валидацию, но и станет отвечать за отправку данных на сервер и обработку ответа.
Пример формы для Bootstrap-фреймворка с атрибутами валидации:
<form class="form-horizontal" role="form" method="POST">
<h1 class="form-signin-heading">Регистрация</h1>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email"
class="form-control"
id="inputEmail3"
name="email"
data-validation="notempty;isemail"
placeholder="Введите ваш email">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">Пароль</label>
<div class="col-sm-10">
<input
type="password"
class="form-control"
id="inputPassword3"
name="password"
data-validation="notempty;minlength:6"
placeholder="Ваш пароль">
</div>
</div>
<div class="form-group">
<label for="inputPassword4" class="col-sm-2 control-label">Повторите пароль</label>
<div class="col-sm-10">
<input type="password"
class="form-control"
id="inputPassword4"
name="password_retry"
data-validation="notempty;passretry"
placeholder="Повторите пароль, вдруг ошиблись при вводе? Мы проверим это.">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div type="submit"
data-input=".form-horizontal"
data-link="<?=URL::to('register')?>"
data-clearinputs="true"
class="btn btn-default senddata">Зарегистрироваться</div>
</div>
</div>
</form>
Теперь, кликая по кнопке «Зарегистрироваться», мы заставим библиотеку проверить данные формы на валидность, а после этого отправить их на сервер и обработать ответ.
Валидация на сервере
Валидацией на сервере должен заниматься тот фреймворк, с которым вы работаете. Библиотека лишь предоставляет класс, упрощающий создание корректного JSON-ответа с командами для клиента.
Но для фреймворка Laravel мною были созданы специальные классы, благодаря которым работа библиотеки в данном фреймворке сводится к дописыванию нескольких строк кода, после чего валидация начинает работать и на сервере.
Чтобы включить валидацию для какого-либо контроллера и модели Laravel, подключите к нужной модели трейт для подключения функционала валидации, а также опишите в ней массив с правилами валидации для полей:
use PrettyFormsLaravelValidatorTrait;
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait, LaravelValidatorTrait;
//...
private $rules = [
'email' => 'required|email|unique:users,email',
'password' => 'required|min:6'
];
}
После этого, в коде обработки запроса, вам остается лишь добавить данный код, который автоматически будет производить валидацию данных перед отправкой, и если что-то пойдёт не так, выполнение будет остановлено, а клиенту будет отправлен ответ с командой отображения ошибок валидации сервера.
use PrettyFormsLaravelResponse;
//...
$user = new User;
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->validateAndSave();
// Ошибок валидации не произошло, генерируем ответ с одной командой: редирект пользователя
return LaravelResponse::generate([
'redirect' => '/login'
]);
Метод LaravelResponse::generate принимает ассоциативный массив из команд и их параметров, которые будут выполнены на клиенской машине. Изначально библиотека поддерживает лишь две команды: validation_errors и redirect. Первая команда используется библиотекой для отправки ошибок формы, вторая — для редиректа пользователя в другое место. Вы можете легко расширить функционал библиотеки, добавив свои собственные обработчики команд, посмотрев на примеры того, как это сделано в оригинальном коде библиотеки.
В общем-то, на этом — всё. Вот таким простым образом можно реализовать валидацию на клиенте и сервере без излишней головной боли, настройки гиганстких плагинов, написания кучи кода в контроллерах, и так далее) Надеюсь, эта библиотека поможет кому-то еще, и я не зря писал весь этот текст)
Проблемы
Библиотека не представляет из себя решение на все случаи жизни и не нацелена на подобное развитие. Это скорее небольшая заготовка, которую вы можете использовать и дорабатывать под свои нужды в своих собственных проектах.
В данный момент, одна из проблем — это невозможность собирать инпуты с теми типами, которые были описаны в стандартах HTML5, хотя их поддержку можно легко добавить в библиотеку, но в данный момент у меня просто не возникало данной необходимости.
Одна из частых проблем — это трудности с получением содержимого из тех полей, к которым применён какой-то дополнительный плагин, вроде Chosen или CKEDitor. Конкретно для двух этих плагинов в библиотеке уже встроена поддержка, и она корректно получает значения из полей, связанных с данными плагинами, но в мире существуют тысячи других плагинов, с которыми она может работать некорректно. Следует учитывать это при использовании библиотеки.
Последние записи
Архив
2023
- Январь (560)
2022
- Декабрь (590)
- Ноябрь (525)
- Октябрь (608)
- Сентябрь (522)
- Август (596)
- Июль (518)
- Июнь (564)
- Май (539)
- Апрель (555)
- Март (586)
- Февраль (492)
- Январь (566)
2021
- Декабрь (554)
- Ноябрь (581)
- Октябрь (611)
- Сентябрь (579)
- Август (587)
- Июль (562)
- Июнь (679)
- Май (713)
- Апрель (665)
- Март (730)
- Февраль (674)
- Январь (681)
2020
- Декабрь (745)
- Ноябрь (672)
- Октябрь (725)
- Сентябрь (635)
- Август (726)
- Июль (801)
- Июнь (896)
- Май (770)
- Апрель (704)
- Март (776)
- Февраль (766)
- Январь (740)
2019
- Декабрь (755)
- Ноябрь (714)
- Октябрь (813)
- Сентябрь (780)
- Август (437)
- Июль (362)
- Июнь (400)
- Май (462)
- Апрель (484)
- Март (514)
- Февраль (493)
- Январь (445)
2018
- Декабрь (505)
- Ноябрь (515)
- Октябрь (513)
- Сентябрь (470)
- Август (539)
- Июль (476)
- Июнь (448)
- Май (486)
- Апрель (586)
- Март (442)
- Февраль (478)
- Январь (485)
2017
- Декабрь (509)
- Ноябрь (584)
- Октябрь (571)
- Сентябрь (341)
- Август (435)
- Июль (538)
- Июнь (450)
- Май (502)
- Апрель (382)
- Март (384)
- Февраль (99)
- Январь (68)
2016
- Декабрь (119)
- Ноябрь (149)
- Октябрь (353)
- Сентябрь (361)
- Август (419)
- Июль (425)
- Июнь (460)
- Май (552)
- Апрель (612)
- Март (502)
- Февраль (192)
- Январь (88)
2015
- Декабрь (82)
- Ноябрь (53)
- Октябрь (37)
- Сентябрь (208)
- Август (330)
- Июль (78)
- Июнь (175)
- Май (365)
- Апрель (448)
- Март (579)
- Февраль (508)
- Январь (915)
2014
- Декабрь (1254)
- Ноябрь (1255)
- Октябрь (1037)
- Сентябрь (844)
- Август (963)
- Июль (820)
- Июнь (920)
- Май (930)
- Апрель (921)
- Март (677)
Категории
- developerslife (1342)
- django (140)
- geektimes (2534)
- github (23687)
- golang (3)
- habrahabr (12140)
- javascript (1461)
- kinopoisk (804)
- megamozg (138)
- pikabu (7701)
- python (1813)
- xaker (10420)
- xkcd (84)
Авторы
- robot
(58889)
Ленты
RSS /
Atom
Просмотров 10к. Опубликовано 19.12.2022
Обновлено 19.12.2022
Каждый сайт, который создает компания, должен отвечать принятым стандартам. В первую очередь затем, чтобы он попадал в поисковую выдачу и был удобен для пользователей. Если код страниц содержит ошибки, неточности, он становится “невалидным”, то есть не соответствующим требованиям. В результате интернет-ресурс не увидят пользователи или информация на нем будет отображаться некорректно.
В этой статье рассмотрим, что такое валидность, какие могут быть ошибки в HTML-разметке и как их устранить.
Содержание
- Что такое HTML-ошибка валидации и зачем она нужна
- Чем опасны ошибки в разметке
- Как проверить ошибки валидации
- Предупреждения
- Ошибки
- Пример прохождения валидации для страницы сайта
- Как исправить ошибку валидации
- Плагины для браузеров, которые помогут найти ошибки в коде
- Коротко о главном
Что такое HTML-ошибка валидации и зачем она нужна
Под понятием “валидация” подразумевается процесс онлайн-проверки HTML-кода страницы на соответствие стандартам w3c. Эти стандарты были разработаны Организацией всемирной паутины и стандартов качества разметки. Сама организация продвигает идею унификации сайтов по HTML-коду — чтобы каждому пользователю, вне зависимости от браузера или устройства, было удобно использовать ресурс.
Если код отвечает стандартам, то его называют валидным. Браузеры могут его прочитать, загрузить страницы, а поисковые системы легко находят страницу по соответствующему запросу.
Чем опасны ошибки в разметке
Ошибки валидации могут разными — видимыми для глаза простого пользователя или такими, которые можно засечь только с помощью специальных программ. В первом случае кроме технических проблем, ошибки в разметке приводят к негативному пользовательскому опыту.
К наиболее распространённым последствиям ошибок в коде HTML-разметки также относят сбои в нормальной работе сайта и помехи в продвижении ресурса в поисковых системах.
Рассмотрим несколько примеров, как ошибки могут проявляться при работе:
- Медленно подгружается страница
Согласно исследованию Unbounce, более четверти пользователей покидают страницу, если её загрузка занимает более 3 секунд, ещё треть уходит после 6 секунд;
- Не видна часть текстовых, фото и видео-блоков
Эта проблема делает контент для пользователей неинформативным, поэтому они в большинстве случаев уходят со страницы, не досмотрев её до конца;
- Страница может остаться не проиндексированной
Если поисковый робот распознает недочёт в разметке, он может пропустить страницу и прервать её размещение в поисковых системах;
- Разное отображение страниц на разных устройствах
Например, на компьютере или ноутбуке страница будет выглядеть хорошо, а на мобильных гаджетах половина кнопок и изображений будет попросту не видна.
Из-за этих ошибок пользователь не сможет нормально работать с ресурсом. Единственное решение для него — закрыть вкладку и найти нужную информацию на другом сайте. Так количество посетителей сайта постепенно уменьшается, он перестает попадать в поисковую выдачу — в результате ресурс становится бесполезным и пропадает в пучине Интернета.
Как проверить ошибки валидации
Владельцы ресурсов используют 2 способа онлайн-проверки сайтов на наличие ошибок — технический аудит или использование валидаторов.
Первый случай подходит для серьёзных проблем и масштабных сайтов. Валидаторами же пользуются ежедневно. Наиболее популярный — сервис The W3C Markup Validation Service. Он сканирует сайт и сравнивает код на соответствие стандартам W3C. Валидатор выдаёт 2 типа несоответствий разметки стандартам W3C: предупреждения и ошибки.
Давайте рассмотрим каждый из типов чуть подробнее.
Предупреждения
Предупреждения отмечают незначительные проблемы, которые не влияют на работу ресурса. Они появляются из-за расхождений написания разметки со стандартами W3C.
Тем не менее, предупреждения всё равно нужно устранять, так как из-за них сайт может работать медленнее — например, по сравнению с конкурентами с такими же сайтами.
Примером предупреждения может быть указание на отсутствие тега alt у изображения.
Ошибки
Ошибки — это те проблемы, которые требуют обязательного устранения.
Они представляют угрозу для корректной работы сайта: например, из-за них могут скрываться разные блоки — текстовые, фото, видео. А в некоторых более запущенных случаях содержимое страницы может вовсе не отображаться, и сам ресурс не будет загружаться. Поэтому после проверки уделять внимание ошибкам с красными отметками нужно в первую очередь.
Распространённым примером ошибки может быть отсутствие тега <!DOCTYPE html> в начале страницы, который помогает информации преобразоваться в разметку.
Пример прохождения валидации для страницы сайта
Рассмотрим процесс валидации на примере сайта avavax.ru, который создали на WordPress.
В результате проверки валидатор выдал 17 замечаний. После анализа отчета их можно свести к 3 основным:
- атрибут ‘text/javascript’ не требуется при подключении скрипта;
- атрибут ‘text/css’ не требуется при подключении стиля;
- у одного из элементов section нет внутри заголовка h1-h6.
Первое и второе замечания генерирует сам движок WordPress, поэтому разработчикам не нужно их убирать. Третье же замечание предполагает, что каждый блок текста должен иметь заголовок, даже если это не всегда необходимо или видно для читателя.
Решить проблемы с предупреждениями для стилей и скриптов можно через добавление кода в файл темы function.php.
Для этого на хук wp_loaded нужно повесить функцию output_buffer_start(), которая загрузит весь генерируемый код html в буфер. При выводе в буфер вызывается функция output_callback($tag), которая просматривает все теги, находит нежелательные атрибуты с помощью регулярных выражений и заменяет их пробелами. Затем на хук ‘shutdown вешается функция output_buffer_end(), которая возвращает обработанное содержимое буфера.
Для исправления семантики на сайте нужно использовать заголовки. Валидатор выдаёт предупреждение на секцию about, которая содержит фото и краткий текст. Валидатор требует, чтобы в каждой секции был заголовок. Для исправления предупреждения нужно добавить заголовок, но сделать это так, чтобы его не было видно пользователям:
- Добавить заголовок в код: <h3>Обо мне</h3>
Отключить отображение заголовка:
1 #about h3 {
2 display: none;
3 }
После этой части заголовок будет в коде, но валидатор его увидит, а посетитель — нет.
За 3 действия удалось убрать все предупреждения, чтобы качество кода устроило валидатор. Это подтверждается зелёной строкой с надписью: “Document checking completed. No errors or warnings to show”.
Как исправить ошибку валидации
Всё зависит от того, какими техническими знаниями обладает владелец ресурса. Он может сделать это сам, вручную. Делать это нужно постепенно, разбирая ошибку за ошибкой. Но нужно понимать, что если при проверке валидатором было выявлено 100 проблем — все 100 нужно обязательно решить.
Поэтому если навыков и знаний не хватает, лучше привлечь сторонних специалистов для улучшения качества разметки. Это могут быть как фрилансеры, так и профессиональные веб-агентства. При выборе хорошего специалиста, результат будет гарантироваться в любом случае, но лучше, чтобы в договоре оказания услуг будут чётко прописаны цели проведения аудита и гарантии решения проблем с сайтом.
Если объём работ большой, выгоднее заказать профессиональный аудит сайта. С его помощью можно обнаружить разные виды ошибок, улучшить внешний вид и привлекательность интернет-ресурса для поисковых ботов, обычных пользователей, а также повысить скорость загрузки страниц, сделать качественную верстку и избавиться от переспама.
Плагины для браузеров, которые помогут найти ошибки в коде
Для поиска ошибок валидации можно использовать и встроенные в браузеры плагины. Они помогут быстро находить неточности еще на этапе создания кода.
Для каждого браузера есть свой адаптивный плагин:
- HTML Validator для браузера Firefox;
- HTML Validator for Chrome;
- HTML5 Editor для Opera.
С помощью этих инструментов можно не допускать проблем, которые помешают нормальному запуску сайта. Плагины помогут оценить качество внешней и внутренней оптимизации, контента и другие характеристики.
Коротко о главном
Валидация — процесс выявления проблем с HTML-разметкой сайта и ее соответствия стандартам W3C. Это унифицированные правила, с помощью которых сайт может нормально работать и отображаться и для поисковых роботов, и для пользователей.
Проверку ресурса можно проводить тремя путями: валидаторами, специалистам полномасштабного аудита и плагинами в браузере. В большинстве случаев валидатор — самое удобное и быстрое решение для поиска проблем. С его помощью можно выявить 2 типа проблем с разметкой — предупреждения и ошибки.
Работать необходимо сразу с двумя типами ошибок. Даже если предупреждение не приведет к неисправности сайта, оставлять без внимания проблемные блоки нельзя, так как это снизит привлекательность ресурса в глазах пользователя. Ошибки же могут привести к невозможности отображения блоков на сайте, понижению сайта в поисковой выдаче или полному игнорированию ресурса со стороны поискового бота.
Даже у крупных сайтов с миллионной аудиторией, например, Яндекс.Дзен или ВКонтакте, есть проблемы с кодом. Но комплексный подход к решению проблем помогает устранять серьёзные моменты своевременно. Нужно развивать сайт всесторонне, чтобы получить результат от его существования и поддержки. Если самостоятельно разобраться с проблемами не получается, не стоит “доламывать” — лучше обратиться за помощью к профессионалам, например, агентствам по веб-аудиту.
Наличие ошибок в коде страницы сайта всегда влечет за собой негативные последствия – от ухудшения позиций в ранжировании до жалоб со стороны пользователей. Ошибки валидации могут наблюдаться как на главной, так и на иных веб-страницах, их наличие свидетельствует о том, что ресурс является невалидным. Некоторые проблемы замечают даже неподготовленные пользователи, другие невозможно обнаружить без предварительного аудита, анализа. О том, что такое ошибки валидации и как их обнаружить, мы сейчас расскажем.
Ошибка валидации, что это такое?
Для написания страниц используется HTML – стандартизированный язык разметки, применяемый в веб-разработке. HTML, как любой другой язык, имеет специфические особенности синтаксиса, грамматики и т. д. Если во время написания кода правила не учитываются, то после запуска сайта будут появляться различные виды проблем. Если HTML-код ресурса не соответствует стандарту W3C, то он является невалидным, о чем мы писали выше.
Почему ошибки валидации сайта оказывают влияние на ранжирование, восприятие?
Наличие погрешностей в коде – проблема, с которой необходимо бороться сразу после обнаружения. Поисковые системы «читают» HTML-код, если он некорректный, то процесс индексации и ранжирования может быть затруднен. Поисковые роботы должны понимать, каким является ресурс, что он предлагает, какие запросы использует. Особо критичны такие ситуации для ресурсов, имеющих большое количество веб-страниц.
Как проверить ошибки валидации?
Для этой работы используется либо технический аудит сайта, либо валидаторы, которые ищут проблемы автоматически. Одним из самых популярных является сервис The W3C Markup Validation Service, выполняющий сканирование с оглядкой на World Wide Web Consortium (W3C). Рассматриваемый валидатор предлагает три способа, с помощью которых можно осуществить проверку сайта:
- ввод URL-адреса страниц, которые необходимо просканировать;
- загрузка файла страницы;
- ввод части HTML-кода, нуждающегося в проверке.
После завершения проверки вы получите развернутый список выявленных проблем, дополненных описанием, ссылками на стандарты W3C. По ходу анализа вы увидите слабые места со ссылками на правила, что позволит самостоятельно исправить проблему.
Существуют другие сервисы, позволяющие выполнить проверку валидности кода:
- Dr. Watson. Проверяет скорость загрузки страниц, орфографию, ссылки, а также исходный код;
- InternetSupervision.com. Отслеживает производительность сайта, проверяет доступность HTML.
Плагины для браузеров, которые помогут найти ошибки в коде
Решить рассматриваемую задачу можно с помощью плагинов, адаптированных под конкретный браузер. Можно использовать следующие инструменты (бесплатные):
- HTML Validator для браузера Firefox;
- HTML Validator for Chrome;
- Validate HTML для Firefox.
После проверки нужно решить, будете ли вы устранять выявленные ошибки. Многие эксперты акцентируют внимание на том, что поисковые системы сегодня уделяют больше внимания качеству внешней/внутренней оптимизации, контенту, другим характеристикам. Однако валидность нельзя оставлять без внимания, ведь если даже обнаруженные проблемы не будут мешать поисковым ботам, то они точно начнут раздражать посетителей сайта.
Как исправить ошибку валидации?
В первую очередь нужно сосредоточить внимание на слабых местах, связанных с контентом – это то, что важно для поисковых систем. Если во время сканирования было выявлено более 25 проблем, то их нельзя игнорировать из-за ряда причин:
- частичная индексация;
- медленная загрузка;
- баги, возникающие во время непосредственной коммуникации пользователя с ресурсом.
Например, игнорирование ошибок может привести к тому, что некоторые страницы не будут проиндексированы. Для решения рассматриваемой проблемы можно привлечь опытного фрилансера, однако лучшее решение – заказ услуги в веб-агентстве, что позволит исправить, а не усугубить ситуацию.
Технический и SEO-аудит
Выявление ошибок – первый шаг, ведь их еще нужно будет устранить. При наличии большого пула проблем целесообразно заказать профессиональный аудит сайта. Он поможет найти разные виды ошибок, повысит привлекательность ресурса для поисковых ботов, обычных пользователей: скорость загрузки страниц, верстка, переспам, другое.
В заключение
На всех сайтах наблюдаются ошибки валидации – их невозможно искоренить полностью, но и оставлять без внимания не стоит. Например, если провести проверку сайтов Google или «Яндекс», то можно увидеть ошибки, однако это не означает, что стоит вздохнуть спокойно и закрыть глаза на происходящее. Владелец сайта должен ставить во главу угла комплексное развитие, при таком подходе ресурс будет наполняться, обновляться и «лечиться» своевременно. Если проблем мало, то можно попробовать устранить их своими силами или с помощью привлечения стороннего частного специалиста. В остальных случаях лучше заказать услугу у проверенного подрядчика.
сентябрь
17
, 2019
Когда мы создаем любые приложения, не стоит рассчитывать, что пользователи будут работать с ним так, как мы задумали. Нет, они постоянно будут делать тупые с нашей точки зрения вещи:
— добавлять товары с пустыми названиями
— прописывать цены строками
— копипастить портянки текста в описания, хотя мы четко написали в инструкции — не больше 200 символов.
Работать с нашим приложением будут не программисты. Представьте менеджера, которому нужно забить в базу 3 сотни товаров, и это до завтра.
Он не будет изучать нашу инструкцию, он сядет и сразу будет набивать по списку. Так сделает любой нормальный человек.
Наша задача, как программистов, сделать так, чтобы система обрабатывала любые данные.
Приложение должно или распарсить эти данные и понять, что хотел ввести пользователь, или приостановить работу и сказать, в чем ошибка.
И сказать человеческим языком, а не ошибкой в консоли. Сегодня мы займемся этой проблемой и посмотрим, как адекватно обрабатывать разные ошибки.
Валидация на клиенте и сервере. В чем разница?
Валидация на клиенте — это те ошибки, которые мы можем проверить средствами браузера. Например,
— юзер пытается добавить товар с пустым названием
— юзер забыл указать цену товара
— юзер вбивает длинное описание, хотя допускается максимум 200 символов.
Все это можно проверить в клиентской части приложения с помощью javascript.
Валидация на сервере — это все то, что можно проверить на клиенте, плюс некоторые специфичные вещи, часто связанные с базой. Например,
— юзер пытается добавить уже существующий товар
— юзер пытается удалить категорию, хотя в ней есть какие-то товары
— юзер пытается удалить бренд, но у него нет прав доступа на это
Все эти вещи проверяются на бекенде, клиент о них не знает.
Отмечу 2 момента:
— стоит по максимуму валидировать данные на клиенте
— дублировать эти же проверки на сервере.
Зачем это нужно?
Валидация на клиенте выполняется быстро и не требует лишнего запроса на сервер. Это ускоряет работу приложения.
Действительно, зачем юзеру ждать, пока запрос сбегает на сервер, если нужно всего лишь проверить, не пустое ли поле названия товара?
Дублировать эти же проверки на сервере нужно для других случаев. Во-первых, нашим приложением могут пользоваться по API, то есть не через интерфейс, а дергать rest-запросы напрямую.
И тут валидация на клиенте не поможет. А во-вторых, могут найтись какие-нибудь хакеры или бродящие по интернету боты, которые захотят поломать наш сервис, закинув в него неподходящие данные.
Вырисовывается простое правило: валидировать на клиенте нужно для нормальных людей, а дублировать те же проверки на сервере — для нехороших ботов и взломщиков.
Валидация в нашей админке интернет-магазина
До какой степени валидировать данные в приложении, каждый решает сам. Процесс этот бесконечный, можно проверять все, что угодно.
Главное, вовремя остановиться и не забыть проверить самые важные вещи.
В нашей админке мы не будем стелить соломку по всему коду, смысл уроков не в этом. Мы подробно рассмотрим валидацию только в одном компоненте, но покроем и клиентские, и серверные проверки.
И научимся показывать юзерам ошибки в человеческом виде.
Мы проработаем форму добавления брендов, которую сделали в прошлом уроке.
Сейчас мы можем добавить любой бренд, потому что никаких проверок нет. Исправим это и будем проверять такие вещи:
— не пустой ли бренд
— не превышает ли бренд 20 символов (практического смысла мало, но для примера нормально)
— существует ли этот бренд в базе
— нет ли ошибки в запросе (неверный роутер, проходили в третьем уроке)
— общие ошибки, например, сервис недоступен, бекенд лежит
Первые 2 проверки будем делать на клиенте, следующие 2 — на сервере. Пятая — это все невошедшие ошибки, например, упавший ajax-запрос или 500-ка от сервера.
Дублировать клиентские проверки на сервере мы не будем. Они очень простые и легко реализуются на php, не будем перегружать код.
Другие серверные ошибки, номер 3 и 4, уже реализованы в третьем уроке, когда мы готовили api для админки.
Общая схема обработки ошибок
Сделаем так. В окошке добавления бренда заведем поле, куда будем выводить сообщение об ошибке.
Пользователям все равно, клиентская это ошибка или серверная, для него это будет выглядеть одинаково, вот так
Чтобы понимать, какая именно ошибка произошла, добавим такое понятие — код ошибки. Например, на скриншоте код «brand_exists», что означает, бренд уже существует.
Это проверка серверная, но красное сообщение об этом не знает.
Код ошибки — единственное, на что будет ориентироваться это сообщение и все равно, откуда он придет, при клиентской валидации или с ответом от сервера.
Тексты сообщений мы будем брать из отдельного конфига. Теперь давайте сделаем это на практике.
Валидация на клиенте
Откроем компонент BrandsNew.vue и добавим новое поле errorCode, в раздел data. Это тот самый код, который определяет наличие ошибки. По умолчанию — пустая строка. То есть вот так
data () { return { visible: false, newBrand: '', // Новое поле errorCode: '' } }
Добавим еще вычисляемое логическое поле isError, которое покажет, если ли в данный момент ошибка
computed: { isError () { return this.errorCode !== ''; } }
Дальше нам нужно вывести сообщение об ошибки в окне добавления бренда. Добавим такой код между инпутом-брендом и кнопкой Добавить
Ошибка: {{errorCode}}
Это выделенный красным текст, пример взяли из библиотеки minicss. Напоминаю, наше приложение на этом css-фреймворке. Чуток поправим стили, добавим в style
mark { display: block; margin: 5px 0 10px 5px; }
Но вернемся к разметке. v-if=»isError» означает, что сообщение будем выводить только, когда есть ошибка, логично. А в тексте сообщения выведем пока код ошибки — {{errorCode}}.
Сначала убедимся, что наша схема работает, а потом заменим бездушный errorCode нормальным текстом.
Итак, errorCode у нас есть, нужны методы для работы с ним. Один метод будет устанавливать код, другой очищать. Добавим в раздел methods
setError (errorCode) { this.errorCode = errorCode; }, clearError () { this.errorCode = ''; }
Можно было обойтись и одним только setError, но позже увидим, что clearError удобная штука и нам еще пригодится.
Базовая подготовка сделана, пора заняться самой валидацией. Напомню, мы будем проверять, что новый бренд не пустой и что не длиннее 20 символов.
Метод валидации будет выполнять эти проверки и в случае ошибкок устанавливать соответствующий код codeError. Вот так выглядит метод validate
validate (brand) { if (brand === '') { this.setError('brand_empty'); return false; } if (brand.length > 20) { this.setError('brand_long_title'); return false; } // Если валидация прошла успешно this.clearError(); return true; }
Два простых if-а, которые проставляют нужные коды brand_empty или brand_long_title. А в случае успеха дергаем метод clearError, чтобы сбросить ошибку, если она была до этого.
Например, юзер ввел правильно инфу со второго раза.
Важный момент. Помимо установки codeError мы возвращаем true или false в зависимости от итога валидации.
Нам это нужно, чтобы понять, отправлять ли запрос на сервер с добавлением бренда или же ждать, пока юзер введет бренд правильно.
Посмотрим, какой метод добавления бренда мы написали раньше
addBrand () { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); }
Все просто, вызываем действие через dispatch, очищаем инпут с названием и закрываем модалку. Этот код нужно чуть переделать, вызывать действие только если валидация прошла успешно.
Добавим условие if
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); } }
На этом с клиентской валидацией все, можно проверять. Пробуем добавить пустой или чересчур длинный бренд, увидим сообщение с нужным кодом ошибки, а запрос на сервер не отправится.
Красота. Идем дальше.
Валидация на сервере
С серверными проверками есть свои особенности.
Во-первых, на клиенте мы генерили коды ошибок сами, а для серверных нужно дождаться ответа и получить их из респонса.
Да, мы эти коды (brand_exists и invalid_router) сами сделали в уроке по API. Но вообще мы можем даже и не знать, что за коды нам возвращает бекенд.
Во-вторых, есть интерфейсный момент. Сейчас в методе addBrand сразу после dispatch мы очищаем поле бренда и закрываем модалку.
Это годится, если бренд успешно добавлен и никуда не годится, если сервер вернул ошибку.
Значит, мы должны не просто дернуть dispatch, а дождаться ответа от сервера и только потом решать, что делать.
Если ответ 200 и бренд добавлен, то закрывать модалку, а если ошибка, то выводить ее и оставлять модалку.
Если бы мы писали приложение на jquery, то сделали бы примерно так
$.ajax({ url: '', data: '', success: function() { // очищаем поле бренда и закрываем модалку }, error: function() { // парсим код ошибки и выводим красное сообщение в модалке } });
Но мы уже серьезные ребята, у нас тут vue и вообще на хабре пишут, что ад из колбеков — это неправильно. Подключим промисы, здесь как раз тот случай, когда без них будет сложно.
Начнем с действия addBrand. Открываем файл store/modules/brands.js и смотрим, как реализовано сейчас
addBrand (context, newBrand) { const data = 'title=' + newBrand; axios .post('/admin/api/v1/brands', data) .then(response => { context.commit('ADD_BRAND', response.data) }); }
Отправляем запрос на сервер через axios и в случае успеха вызываем мутацию ADD_BRAND. Нам нужно сделать то же самое, только при этом еще и возвращать промис. Вот так
addBrand (context, newBrand) { const data = 'title=' + newBrand; return new Promise((resolve, reject) => { axios .post('/admin/api/v1/brands', data) .then(response => { context.commit('ADD_BRAND', response.data); resolve(response); }, error => { reject(error); }); }); }
Это стандартная заготовка для промисов. resolve и reject — это функции, которые выполняются соответственно при успехе и ошибке.
А что именно делают эти функции, будем решать уже в другом месте — опять в компоненте BrandsNew, в методе addBrand. Немного изменим код.
Было
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand); this.newBrand = ''; this.closeModal(); } }
Стало
addBrand () { if (this.validate(this.newBrand)) { this.$store.dispatch('brands/addBrand', this.newBrand).then( response => { this.newBrand = ''; this.closeModal(); }, error => { let resp = error.response; let errorCode = (resp && resp.data && resp.data.code) ? resp.data.code : 'unknown_error'; this.setError(errorCode); }); } }
Кода прибавилось, но немного. В метод resolve попадает
response => { this.newBrand = ''; this.closeModal(); }
Параметр response нам не нужен, просто для наглядности. Получается, если запрос прошел успешно, бренд добавлен, то очищаем поле в модалке и саму модалку закрываем.
При ошибке выполняется другое
error => { let resp = error.response; let errorCode = (resp && resp.data && resp.data.code) ? resp.data.code : 'unknown_error'; this.setError(errorCode); });
Здесь параметр error уже нужен — это ответ от сервера, который нужно распарсить и вытащить код ошибки. Разберем по порядку. В первой строке пишем в переменную resp ответ от сервера.
Дальше идет диковатая конструкция resp && resp.data && resp.data.code. Зачем так сложно?
Ведь мы возвращаем ответ с бекенда в виде { code: ‘код ошибки’, … }, то есть поле code там будет всегда. Не совсем.
Код будет, но только для тех случаев, когда наш бекенд нормально обработает ошибку. Например, найдет, что бренд уже существует, или невалидный роутер (ошибка в запросе, в урле).
Если же бекенд просто лежит и вернет нам 500-ку, то в error.response может прийти null или пустая строка. Поэтому resp.data.code выкинет нам ошибку в консоль и поломает работу.
Поэтому именно здесь мы подстилаем соломку и проверяем всю цепочку error.response.data.code.
Только если data.code действительно существует, то мы понимаем, что эту ошибку вернул наш бекенд и в errorCode мы записываем валидное значение.
А в противном случае мы понимаем, что случилась какая-то хрень и поэтому ставим unknown_error. Типа «случилась непонятная хрень». Так и напишем пользователю.
Задача программиста как можно меньше пугать юзеров непонятными ошибками и стараться по максимуму обрабатывать их руками.
Другое дело, что пользователям вообще по фигу, лежит ли у вас бекенд, упала ли база и кто-то накосячил в коде. Ему важно, что приложение не работает и все.
Поэтому есть смысл не перегружать юзера техническими деталями, а выдать общую ошибку и попросить попробовать позже. Естественно, предполагается, что мы уже устраняем косяки и поднимаем бекенд.
Это все, что касается валидации на сервере. Можно проверять, попытаться добавить существующий бренд или изменить урл /admin/api/v1/brands на какой-нибудь левый.
Если все сделали правильно, то при добавлении бренда будет уходить запрос на сервер, возвращаться ошибка и модалка не закроется, а выведет код.
Когда мы будем тестировать работу, то заметим одну визуальную неприятность. Допустим, попытались мы добавить пустой бренд, нам выскочила ошибка brand_empty.
Изменяем бренд в инпуте, а ошибка так и торчит. Бесит. Давайте добавим одну строчку, чтобы при установке фокуса в инпуте ошибка пропадала. Теперь инпут будет выглядеть так
@focus=»clearError» — вот и пригодился метод clearError!
Вывод нормального сообщения об ошибке вместо кода
Коды ошибок у нас есть, осталось задать им адекватные тексты. Можно сделать это и в компоненте BrandsNew, но мы поступим интереснее.
Заведем в папке admin/vue/src папку configs, а в ней файлик brands.js. Давно было пора, потому что хорошее дело — выносить подобные вещи в конфиги, а не держать их в компонентах.
В файлике-конфиге напишем так
export default { errors: [{ code: 'brand_empty', message: 'Бренд не может быть пустым' }, { code: 'brand_long_title', message: 'Название не должно превышать 20 символов' }, { code: 'brand_exists', message: 'Бренд с таким названием уже существует' }, { code: 'invalid_router', message: 'Ошибка запроса. Попробуйте еще раз' }, { code: 'unknown_error', message: 'Неизвестная ошибка. Попробуйте позже' }] }
Просто массив из двух полей: код ошибки и текст сообщения. Можно было обойтись объектом, чтобы не бегать по массиву. Но на практике такие простые конфиги часто разрастаются.
То появится тултип с подробным описанием ошибки, то для каждой ошибки нужен будет свой цвет или еще какая-то фигня. Или вместо текстового кода мы решим использовать числовой.
В общем, чтобы не приходилось переделывать структуру конфига, сразу будем использовать массив объектов — в него добавлять новые поля безопасней.
Идем обратно в компонент BrandsNew. В теге script импортируем lodash и конфиг брендов
import _ from 'lodash'; import config from '../configs/brands';
Создаем новое вычисляемое поле в computed
errorMessage () { return this.errorCode !== '' ? _.find(config.errors, { code: this.errorCode }).message : ''; }
Это и есть сообщение об ошибке, которое берется из конфига по нужному коду. Осталось воткнуть его в разметку вместо errorCode. Вот так
{{errorMessage}}
Вот теперь все. У нас есть рабочая схема, по которой мы обрабатываем и клиентские, и серверные ошибки, используя один формат данных.
Теперь чтобы добавить новую проверку, достаточно будет воткнуть ее в метод validate, если проверка клиентская, и в php-шный код, если серверная.
Главное, вернуть с бекенда json формата { code: ‘код ошибки’, … }. И добавить новый объект в конфиг, чтобы показывать адекватные тексты пользователям.
До встречи в следующих уроках.
Все уроки админки на vue.js
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Серверная валидация пользовательских данных
Время на прочтение
5 мин
Количество просмотров 8.6K
Доброго времени, хаброчеловеки!
Мне хотелось бы поднять тему серверной валидации пользовательских данных. Поискав на хабре топики данной тематики и погуглив, пришёл к выводу, что люди часто изобретают свои собственные велосипеды для реализации механизма валидации. В данной статье хочу рассказать о простом и красивом решении, которое успешно применяется в нескольких проектах.
Проблема
Часто замечаю, что разработчики активно используют исключения (exceptions) для уведомления об ошибках валидации данных. Продемонстрирую примером (поскольку C# мне ближе, буду использовать его):
public void Validate(string userName, string userPassword)
{
if (/*проверяем имя пользователя*/)
throw new InvalidUsernameException();
if (/*проверяем пароль*/)
throw new InvalidPasswordException();
}
Далее это используется примерно так:
public void RegisterUser (string username, string password) {
try {
ValidateUser(username, password);
}catch(InvalidUsernameException ex) {
//добавляем в коллекцию ошибок
}catch(InvalidPasswordException ex) {
//добавляем в коллекцию ошибок
}//что-то дальше делаем
}
Что плохого в этом примере?
— используются исключения (exceptions) на этапе бизнес валидации. Важно помнить, что ошибки валидации данных != ошибкам работы приложения;
— использование исключений на этапе бизнес валидации может привести к падению приложения. Такое может произойти, например, если человек забудет написать ещё один блок catch для новых правил валидации;
— код выглядит некрасиво;
— подобное решение сложно тестировать и поддерживать.
Решение
Механизм валидации данных можно реализовать при помощи паттерна Composite (компоновщик).
Нам потребуется непосредственно сам объект валидатор, который непосредственно проверяет данные на соответствие определённым правилам, композитный валидатор, который инкаплусирует в себе коллекцию валидаторов, а также дополнительный класс, используемый в
качестве хранилища результата валидации и коллекции ошибок — ValidationResult. Рассмотрим вначале последний:
public class ValidationResult{
private bool isSucceedResult = true;
private readonly List<ResultCode> resultCodes = new List();protected ValidationResult() {
}public ValidationResult(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}public static ValidationResult SuccessResult {
get { return new ValidationResult(); }
}public List<ResultCode> GetResultCodes {
get { return resultCodes; }
}public bool IsSucceed {
get { return isSucceedResult; }
}public void AddError(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}public void Merge(ValidationResult result) {
resultCodes.AddRange(result.resultCodes);
isSucceedResult &= result.isSucceedResult;
}
}
Теперь перейдём непосредственно к механизму валидации. Нам необходимо создать базовый класс Validator, от которого будут наследоваться все валидаторы:
public abstract class Validator {
public abstract ValidationResult Validate();
}
У объектов-валидаторов существует 1 метод, который запускает процедуру проверки и возвращает результат.
CompositeValidator — класс, содержащий в себе коллекцию валидаторов и запускающий механизм проверки у всех дочерних объектов:
public class CompositeValidator : Validator {
private readonly List<Validator> validators = new List();public void Add(Validator validator) {
validators.Add(validator);
}public void Remove(Validator validator) {
validators.Remove(validator);
}public override ValidationResult Validate() {
ValidationResult result = ValidationResult.SuccessResult;
foreach (Validator validator in validators) {
result.Merge(validator.Validate());
}
return result;
}
}
Используя эти классы, мы получили возможность создавать валидаторы с определёнными правилами, комбинировать их и получать результаты проверки.
Использование
Перепишем приведённый в начале статьи пример с использованием этого механизма. В нашем случае необходимо создать 2 валидатора, которые проверяют имя пользователя и пароль на соответствие определённым правилам.
Создаём объект для проверки имени пользователя UserNameValidator:
public class UserNameValidator: Validator {
private readonly string userName;public UserNameValidator(string userName) {
this.userName= userName;
}public override ValidationResult Validate() {
if (/*параметр не прошёл проверку на условие, например userName = null*/) {
return new ValidationResult(ResultCode.UserNameIncorrect);
}return ValidationResult.SuccessResult;
}
}
Аналогично получаем UserPasswordValidator.
Теперь у нас есть всё, чтобы использовать новый механизм валидации данных:
public ValidationResult ValidateUser(string userName, string userPassword)
{
CompositeValidator validator = new CompositeValidator();
validator.add(new UserNameValidator(userName));
validator.add(new UserPasswordValidator(userPassword));return validator.Validate();
}public void RegisterUser (string username, string password) {
ValidationResult result = ValidateUser(username, password);if (result.IsSucceed) {
//успешная валидация
}else {
//получаем ошибки валидации result.GetResultCodes() и обрабатываем соответствующим образом
}}
Выводы
Какие преимущества мы получили, используя данный подход:
— расширяемость. Добавление новых валидаторов стоит дешево;
— тестируемость. Все валидаторы могут быть модульно протестированы, что исключает наличие ошибок в общем процессе валидации;
— сопровождаемость. Валидаторы можно выделить в отдельную сборку и использовать во многих проектах с незначительными изменениями;
— красота и правильность. Данный код выглядит красивее, изящнее и правильнее, первоначального варианта, исключения не используются для бизнес валидации.
Заключение
В дальнейшем можно применить несколько улучшений к механизму валидации, а именно:
— инкапсулировать все валидаторы в одну сборку и создать фабрику, которая будет возвращать готовый механизм валидации для различных условий (проверка данных для регистрации пользователя, проверка данных при авторизации и т.д.);
— базовый класс Validator можно заменить на интерфейс, кому как нравится;
— правила валидации можно хранить в одном месте, для более удобного управления;
— можно написать обработчик ошибок валидации, который будет сопоставлять коды ошибок и сообщения, выводимые пользователям на UI, в таком случае ещё сильнее упрощается процесс добавления новых валидаторов. Также отпадает проблема локализации сообщений.
P.S.
Просьба сильно не пинать за возможные ошибки в написании и изложении. Я очень старался)
С удовольствием выслушаю критику и пожелания по поводу реализации и архитектуры.
* All source code was highlighted with Source Code Highlighter.