А оно нам действительно нужно?

Когда мы приступили к разработке корпоративного клиента, мы попросили нашего UX-дизайнера дать нам несколько советов по дизайну, как обрабатывать ошибки внутреннего сервера в приложении. Должно ли это быть всплывающее окно, тостер или сообщение об ошибке рядом с вводом?
Его ответ был не таким, как мы ожидали: «в вашем приложении не должно быть ошибок вообще. ! '
Мы объяснили, что в нашем приложении пользователь может выполнять множество недопустимых действий, которые не разрешены, и нам нужно показать ошибку с внутреннего сервера. В конце концов, это корпоративное приложение…
Его ответ был довольно справедливым: не позволять пользователю совершать действия, которые нельзя делать.
Итак, о чем еще нам нужно беспокоиться? Неожиданные ошибки, поскольку для ожидаемых ошибок мы можем составить план, и хороший поток пользовательского интерфейса.
Неожиданные ошибки носят очень технический характер, и простой пользователь ничего не может сделать с этой информацией (блокировка БД, синтаксическая ошибка запроса, исключение нулевого указателя, разорванное соединение…). Так что достаточно сказать пользователю, что «что-то пошло не так».
В таких случаях хорошим UX-поведением является показ всплывающего окна или любое другое неприятное решение, которое вы хотите.

Разработайте наш обработчик ошибок

Мы хотим создать службу, которая обнаруживает любые непредвиденные ошибки в приложении, например следующие:

  • Если это ошибка нашего внутреннего сервера, то мы хотим показать тостер с некоторым сообщением о том, что что-то пошло не так, и пользователь может повторить попытку позже ... когда пользователь щелкнет, чтобы закрыть его, страница будет обновлена ​​(мы позже предложу лучшее решение).
  • Если это неавторизованная ошибка (срок действия сеанса истек), перейдите пользователя на страницу входа в систему.
  • Если это запрещено, переместите пользователя на страницу, описывающую, что ему необходимы дополнительные разрешения для выполнения этого действия.

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

Давайте сделаем это шаг за шагом:

  1. Реализовать ErrorHandler

Angular имеет интерфейс ErrorHandler in@angular/core. Давайте создадим новый класс, который будет его реализовывать.

2. Выполните handleError(error: any): void

Некоторые примечания:

  1. Я использовал две внешние библиотеки: ng2-toastr и http-status-codes (если вы использовали машинописный текст, вам нужно будет добавить @ types / http-status-codes)
  2. У всех наших внутренних ошибок есть поле httpErrorCode.. Мы используем его, чтобы различать разные типы ошибок. Если такого поля нет, возможно, это ошибка, вызванная клиентским кодом.

3. Предоставьте нашу услугу в корневом модуле: (пожалуйста, root, чтобы сделать его одноэлементным)

provide: ErrorHandler,useClass: MyAppErrorHandler

И мы закончили !!!

Давайте сделаем еще один шаг:

Обновление страницы - не лучшее решение. Итак, что лучше? Это зависит от нашего варианта использования. Давайте дадим нашим компонентам / службам пользовательского интерфейса возможность отправлять обратный вызов в объекте ошибки. Наша служба обработки ошибок вызовет его, и когда пользователь отклонит ошибку, она появится в всплывающем сообщении.

В приведенном ниже коде у меня есть служба для удаления элемента, вызов некоторого внутреннего API, чтобы удалить его тоже. И в случае ошибки я добавляю к объекту ошибки обратный вызов, который знает, что нужно повторно добавить удаленный элемент.
Сценарий будет следующим: пользователь удаляет элемент, получает сообщение: «что-то пошло не так, повторите попытку позже», пользователь нажимает на сообщение, чтобы закрыть элемент, добавляется снова в список, как и до исключения.

Наш обработчик будет немного изменен: вместо вызова наивного обновления: window.location.reload мы сделаем error.callback?error.callback():window.location.reload;

Это достаточно?

Я предпочитаю исключить работу по структурированию ошибок из нашей логики компонента и переместить ее в область HTTP-запроса. Компонент просто знает, что нужно подготовить обратный вызов и отправить его службе, которая выполняет HTTP. Он будет структурировать обратный вызов внутри объекта ошибки и повторно выбросить.

Теперь наш deletItem API будет проще:

И внутренний HTTP-запрос будет:

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