Одним из признаков профессионально созданного сайта я считаю наличие обработчиков ошибок 404 (ресурс не найден) и 500 (внутренняя ошибка сервера). Это может быть как статический файл, так и код выполняющий необходимые разработчику действия. Я уже затрагивал эту тему в заметке Обработка ошибки 500 в ASP.NET, но возвращаюсь к ней так как смог найти способ универсальной обработки http ошибок в приложении ASP.NET.
Зачем нужна обработка ошибок на сайте?
- Забота о посетителе сайта, который должен видеть понятное объяснение того, что произошло. Стандартные тексты ошибок понятны только специалистам. Кроме того, если сайт на русском языке, то логично чтобы и текст ошибки был на русском.
- Протоколирование ошибок. Разработчик должен иметь возможность знать о том, что на сайте произошла ошибка. На небольшом сайте можно проверить работоспособность каждой страницы, но с какого-то предела это становится трудновыполнимым, если вообще возможным. Текст ошибки можно отправлять разработчикам по электронной почте, заносить в EventLog или использовать любые другие способы.
- Безопасность. Посетителю сайта незачем видеть подробный текст ошибки. Технические детали ошибки могут помочь злоумышленнику взломать сайт. К счастью, стандартные настройки ASP.NET не позволяют выдавать полный текст ошибки всем посетителям.
Стандартный способ обработки ошибок в ASP.NET предполагает использование секции customErrors файла web.config. Его серьезным недостатком является то, что в случае ошибки посетитель сайта перенаправляется с запрошенной страницы на страницу обработчик. Самые большие неудобства это создает при внутренней ошибке сервера, так как посетитель лишен возможности использовать кнопку браузера "обновить". Я хочу предложить решение свободное от данного недостатка. Итак, код:
[Обновление от 16 февраля 2005: в строке 8 была ошибка. Не все исключения приходящие в Application_Error являются объектами типа HttpException и в таком случае можно предполагать что код ошибки 500]
1 protected void Application_Error(object sender, EventArgs e)
2 {
3 // Не обрабатывать ошибки в режиме отладки
4 //if (GlobalVariables.IsDebugMode) return;
5
6 // Обрабатываем только ошибки 404 и 500
7 HttpException error = Server.GetLastError() as HttpException;
8 int httpCode = (null != error) ? error.GetHttpCode() : 0;
8 int httpCode = (null != error) ? error.GetHttpCode() : 500;
9 if (404!=httpCode && 500!=httpCode) return;
10
11 Server.ClearError();
12 Response.Clear();
13 Response.StatusCode = httpCode;
14
15 // Показать посетителю сообщение об ошибке
16 switch (httpCode)
17 {
18 case 404:
19 Response.WriteFile(Server.MapPath("/error404.html"));
20 break;
21
22 case 500:
23 Response.WriteFile(Server.MapPath("/error500.html"));
24 break;
25 }
26 }
Данный пример является простейшим обработчиком ошибок 404 и 500. В случае ошибки посетителю показываются файлы с соответствующим сообщением (файлы error404.html и error500.html должны находиться в корне сайта). Определение кода ошибки выполняется в строках 7-9. Если возникшее исключение имеет тип System.Web.HttpException, то мы получаем http код ошибки и решаем, обрабатывать ошибку или нет.
Таким образом, посетитель сайта будет видеть дружелюбное описание ошибки, но что делать разработчику сайта, который хочет (и имеет полное право) видеть настоящий текст ошибки ASP.NET. Тут можно использовать два решения: обернуть код Application_Error в блок #if (!DEBUG) ... #endif, так чтобы функция Application_Error компилировалась только для release версии сайта или создать глобольное свойство, возвращающее true для отладочного приложения и false в противном случае (смотри строки 3-4 примера). Последний вариант можно реализовать, проверяя имя и/или ip-адрес сервера/клиента или любым другим способом. Безусловно, эта проверка должна быть написана так чтобы ее нельзя было обмануть. Я рекомендую использовать вариант с директивами условной компиляции.
Секцию customErrors в файле web.config в таком случае можно оставить пустой, указав только атрибут mode="On", как рекомендуется компанией Microsoft.
При создании текстов ошибок в файлах error404.html и error500.html не забывайте, что их длина должна быть больше 511 байтов, иначе Internet Explorer может показать собственную страницу с описанием ошибки. Подробности читайте в статье HOW TO: Turn Off the Internet Explorer 5.x and 6.x "Show Friendly HTTP Error Messages" Feature on the Server Side.
[Дополнение от 16 марта 2006] Существует возможность изменения длины запроса по которому MSIE решает показывать ли ему собственное сообщение об ошибке или ответ сервера. Эти настройки хранятся в ключе реестра HKLM\Software\Microsoft\Internet Explorer\Main\ErrorThresholds. Подробности в статье Description of Hypertext Transport Protocol Error Messages.