Урок 2 кастомные страницы ошибок тестирование страницы 404

10 июля, 2015 12:54 пп
1 573 views
| Комментариев нет

Centos, Cloud Server, VPS

Apache – самый популярный в мире веб-сервер; многофункциональный и гибкий, он постоянно развивается и поддерживается командой высококвалифицированных специалистов.

При проектировании веб-страниц часто возникает необходимость настроить каждую страницу индивидуально. Это касается и страниц ошибок, которые появляются, если запрашиваемый контент по какой-либо причине недоступен. В этом руководстве показано, как настроить Apache для отображения пользовательских страниц ошибок в системе CentOS 7.

Требования

Для выполнения данного руководства нужна уётная запись пользователя с привилегиями sudo. Чтобы настроить такого пользователя, обратитесь к этому руководству. Кроме того, нужно предварительно установить Apache; подробные инструкции по установке веб-сервера можно получить здесь.

Создание пользовательской страницы ошибок

Для начала создайте пользовательские страницы ошибок.

Примечание: Для тестирования можно использовать следующий код без изменений. Чтобы создать свою страницу ошибок, просто замените текст в echo в приведённом ниже коде.

Страницы ошибок будут находиться в каталоге /var/www/html – стандартном каталоге document root веб-сервера Apache. Для примера создайте страницу ошибки 404 (по имени custom_404.html) и общую страницу для ошибок 500 (назовите её custom_50x.html).

echo "<h1 style='color:red'>Error 404: Not found :-(</h1>" | sudo tee /var/www/html/custom_404.html
echo "<p>I have no idea where that file is, sorry.  Are you sure you typed in the correct URL?</p>" | sudo tee -a /var/www/html/custom_404.html
echo "<h1>Oops! Something went wrong...</h1>" | sudo tee /var/www/html/custom_50x.html
echo "<p>We seem to be having some technical difficulties. Hang tight.</p>" | sudo tee -a /var/www/html/custom_50x.html

Итак, теперь на сервере есть две страницы ошибок.

Настройка Apache для отображения пользовательских страниц ошибок

Теперь нужно настроить Apache для поддержки только что созданных страниц в случае возникновения соответствующей ошибки. Создайте новый конфигурационный файл в каталоге /etc/httpd/conf.d, который хранит настройки для Apache. Назовите файл custom_errors.conf:

sudo nano /etc/httpd/conf.d/custom_errors.conf

Направьте Apache на соответствующие страницы ошибок.

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

В данном случае настройки будут выглядеть так:

/etc/httpd/conf.d/custom_errors.conf
ErrorDocument 404 /custom_404.html
ErrorDocument 500 /custom_50x.html
ErrorDocument 502 /custom_50x.html
ErrorDocument 503 /custom_50x.html
ErrorDocument 504 /custom_50x.html

Этих настроек достаточно, чтобы обслуживать пользовательские страницы ошибок.

Однако рекомендуется добавить ещё один блок конфигураций, чтобы клиенты не могли запрашивать страницы ошибок напрямую. Это предотвратит путаницу (например, запрошенная напрямую страница ошибки будет сообщать пользователю об ошибке, даже если код состояния – 200 (Success)).

Чтобы настроить такое поведение веб-сервера, нужно добавить блок Files для каждой пользовательской страницы ошибок. Также нужно проверить, установлена ли переменная окружения REDIRECT_STATUS; она должна быть установлена только если директива ErrorDocument обрабатывает запрос. Если переменная окружения пуста, сервер будет обслуживать страницу 404:

/etc/httpd/conf.d/custom_errors.conf
ErrorDocument 404 /custom_404.html
ErrorDocument 500 /custom_50x.html
ErrorDocument 502 /custom_50x.html
ErrorDocument 503 /custom_50x.html
ErrorDocument 504 /custom_50x.html
<Files "custom_404.html">
<If "-z %{ENV:REDIRECT_STATUS}">
RedirectMatch 404 ^/custom_404.html$
</If>
</Files>
<Files "custom_50x.html">
<If "-z %{ENV:REDIRECT_STATUS}">
RedirectMatch 404 ^/custom_50x.html$
</If>
</Files>

Когда страницы ошибок запрашиваются клиентами, возникает ошибка 404, потому что переменная среды не установлена.

Тестирование страницы ошибок 500

Проверить работу страницы ошибок 404 очень просто: нужно запросить любой несуществующий контент. Чтобы протестировать страниц ошибок 500, нужно создать фиктивный ProxyPass.

Добавьте директиву ProxyPass в конец конфигурационного файла. Отправьте запросы для /proxytest на порт 9000 на локальной машине (на этом порте не запущено ни одного сервиса):

/etc/httpd/conf.d/custom_errors.conf
ErrorDocument 404 /custom_404.html
ErrorDocument 500 /custom_50x.html
ErrorDocument 502 /custom_50x.html
ErrorDocument 503 /custom_50x.html
ErrorDocument 504 /custom_50x.html
<Files "custom_404.html">
<If "-z %{ENV:REDIRECT_STATUS}">
RedirectMatch 404 ^/custom_404.html$
</If>
</Files>
<Files "custom_50x.html">
<If "-z %{ENV:REDIRECT_STATUS}">
RedirectMatch 404 ^/custom_50x.html$
</If>
</Files>
ProxyPass /proxytest "http://localhost:9000"

Сохраните и закройте файл.

Тестирование страниц ошибок

Проверьте конфигурационный файл на наличие ошибок:

sudo apachectl configtest

Если команда обнаружила любые ошибки, исправьте их. После этого перезапустите Apache:

sudo systemctl restart httpd

Откройте домен или IP-адрес сервера и запросите несуществующий контент, чтобы проверить работу страницы 404:

http://server_domain_or_IP/thiswillerror

На экране должна появиться страница 404:

Error 404: Not found :-(
I have no idea where that file is, sorry.  Are you sure you typed in the correct URL?

Откройте фиктивный proxypass, чтобы проверить работу страницы 500 (на экране должен появиться код состояния 503 service unavailable):

http://server_domain_or_IP/proxytest

Если всё настроено верно, на экране появится:

Oops! Something went wrong...
We seem to be having some technical difficulties. Hang tight.

После тестирования удалите фиктивную директиву из конфигураций Apache.

Заключение

Итак, теперь на сайте есть уникальные страницы ошибок. Пользовательские страницы ошибок – это отличный способ помочь посетителям понять, в чём дело, предоставить им всю необходимую информацию об ошибке и полезные ссылки (не забудьте убедиться, что ссылки работают даже в случае возникновения ошибок).

Tags: Apache, CentOS 7

Режим отладки проекта

Сейчас ваш проект работает в режиме отладки: при установке проекта в конфиге был автоматически выставлен флаг DEBUG=True. В этом режиме при ошибках выводится страница с технической информацией и подробным разбором строк, в которых что-то пошло не так.

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

При публикации сайта на боевом сервере режим разработки нужно отключать. Тогда при ошибках вместо отладочных страниц будут отображаться просто страницы с сообщениями об ошибке.

Страницы ошибок

Чтобы отключить режим отладки (его ещё называют «режим разработки» или «режим разработчика»), в settings.py нужно установить значение DEBUG=False. После этого страницы с ошибками вы увидите в совершенно ином виде.

В Django есть предустановленные страницы ошибок (например, для ошибки 404 — «страница не найдена» или для 403 — «запрос отклонён»); однако выглядят эти страницы так, будто разработчику сайта не было до них дела. Нельзя оставлять их в таком виде: пользователи будут неприятно изумлены.

Создадим собственные страницы ошибок; они относятся ко всему проекту, поэтому будет логично описать их view-функции и шаблоны в приложении core.

Ошибка 404: страница не найдена

Подготовим view-функцию для страницы 404:

# core/views.py
from django.shortcuts import render

def page_not_found(request, exception):
    # Переменная exception содержит отладочную информацию; 
    # выводить её в шаблон пользовательской страницы 404 мы не станем
    return render(request, 'core/404.html', {'path': request.path}, status=404)
 

Шаблон этой страницы будет таким:

# templates/core/404.html
{% extends "base.html" %}
{% block title %}Custom 404{% endblock %}
{% block content %}
  <h1>Custom 404</h1>
  <p>Страницы с адресом {{ path }} не существует</p>
  <a href="{% url 'home:index' %}"> Идите на главную</a>
{% endblock %} 

Django распознаёт ошибки и вызывает для их обработки заготовленные view-функции. Имена этих функций хранятся в специальных переменных — хендлерах (англ. handlers). Адрес view-функции с ошибкой 404 хранится в переменной handler404 (по умолчанию это view-функция django.views.defaults.page_not_found).

Хендлер можно переопределить: передать в него имя собственной view-функции. Для этого достаточно добавить в головной url-файл проекта такую строчку:

# urls.py

handler404 = 'core.views.page_not_found'
 

В результате при ошибке 404 отработает view-функция page_not_found() и отобразится кастомная страница ошибки. А уж настроить эту страницу — дело фронтендера.

Разумеется, дизайн может быть каким угодно.

Обработка прочих ошибок выполняется точно так же. В Django заготовлены переменные handler400handler403 и несколько других, в документации есть их перечень.

403: ошибка проверки CSRF, запрос отклонён

Ошибка 403 в Django появится в том случае, если при отправке формы не был отправлен csrf-токен. Страница этой ошибки кастомизируется немного иначе: view-функция и шаблон готовятся, как и для других страниц, но переопределяется не хандлер, а константа CSRF_FAILURE_VIEW в settings.py.

View-функция:

# core/views.py
from django.shortcuts import render

def csrf_failure(request, reason=''):
    return render(request, 'core/403csrf.html')
 

Шаблон:

# templates/core/403csrf.html
{% extends "base.html" %}
{% block content %}
  <h1>Custom CSRF check error. 403</h1>
{% endblock %} 

Имя view-функции, обрабатывающей ошибку 403, указывается в settings.py, в константе CSRF_FAILURE_VIEW:

PYTHON# settings.py

CSRF_FAILURE_VIEW = 'core.views.csrf_failure'
 

Включение и отключение режима отладки

При разработке реальных проектов вы будете публиковать их на сервере, при этом нужно будет отключать режим отладки. Для этого в файле settings.py нужно установить значение ключа DEBUG=False.

После отключения режима разработки у вас перестанет показываться статика. Это нормально: в «боевом режиме» Django ожидает, что статику будет раздавать специально настроенный сервер.

После отключения режима разработки может возникнуть и другая проблема: при обращении к страницам сайта может вернуться ошибка 400: Bad Request. Эта ошибка может возникнуть как на локальном компьютере, так и на удалённом сервере.

Причина — в settings.py в списке ALLOWED_HOSTS не указан адрес вашего сервера.

Проверьте этот список, в нём должны быть указаны адреса, на которых может быть размещён проект:

DEBUG = False

ALLOWED_HOSTS = [
    'localhost',
    '127.0.0.1',
    '[::1]',
    'testserver',
] 

После проверки работы шаблонов не забудьте вернуть сайт в режим разработки:

DEBUG = True 

Яндекс.Практикум

курс Python-разработчик

студент Leonid Slavutin

Проект sprint_6. Подписки на авторов.


Шаблоны и структура проекта заданы.

Задачи проекта:

  • В проект добавлены кастомные страницы ошибок:

    404 page_not_found

    500 server_error

    403 permission_denied_view

    Написан тест, проверяющий, что страница 404 отдает кастомный шаблон.

  • С помощью sorl-thumbnail выведены иллюстрации к постам.

    Написаны тесты, которые проверяют работу с изображениями.

  • Создана система комментариев

  • Добавлены:

    Кеширование главной страницы

    Тестирование кэша

  • Добавлена система подписки на авторов.


Разворачивание проекта:

Клонировать репозиторий и перейти в его папку в командной строке:

git clone https://github.com/coherentus/hw05_final
cd hw05_final

Cоздать и активировать виртуальное окружение:

Для *nix-систем и MacOS:

Для windows-систем:

source venv/Scripts/activate

Установить зависимости из файла requirements.txt:

python3 -m pip install --upgrade pip
pip install -r requirements.txt

Выполнить миграции:

cd yatube
python3 manage.py migrate

Запустить проект:

python3 manage.py runserver

Создать суперпользователя Django:

python3 manage.py createsuperuser

Сам проект и админ-панель по адресам:

http://127.0.0.1:8000

http://127.0.0.1:8000/admin

В зависимости от задач можно по-разному переопределить в Django стандартное поведение на реакцию ошибок, таких как 403, 404, 500 и стандартные шаблоны вывода ошибок. В официальной документации (на рус. яз. — http://djbook.ru/rel1.8/topics/http/views.html) хорошо это описывается, но тем не менее есть некоторые нюансы, о которых я хочу рассказать и показать в примерах.

В большинстве случаев можно оставить стандартное поведение Django, т. е. стандартные views (из django.views.defaults), обрабатывающие ошибки и переопределить только шаблоны.

Допустим, у нас есть шаблон ошибки 404:

# 404.html
{% extends "base.html" %}

{% block subtitle %}Страница не найдена{% endblock %}
{% block meta %}<meta name="robots" content="noindex, nofollow">{% endblock %}

{% block content %}
    <h2>Запрашиваемая страница не найдена</h2>
    <p>Возможно, неправильно указан путь в адресной строке или страница была удалена.</p>
    <p>Возврат на <a href="/">главную страницу</a></p>
{% endblock %}

А ниже описаны разные способы переопределения.

Добавление своего шаблона в templates

Самый простой способ переопределения — это добавить этот шаблон в «my_project / templates». Именно здесь django будет искать шаблон 404.html и при наличии отрендерит.

Добавление своего шаблона в другую папку

Не всегда удобно держать шаблоны ошибок в «my_project / templates» вместе с какими-то другими шаблонами и хочется их вынести в отдельную папку. Я, к примеру, использую следующую структуру папки templates в корне проекта (жирным выделены папки):

  • admin — содержит переопределяемые админские шаблонов
  • cms — содержит переопределяемые шаблоны Django CMS
  • errs — содержит шаблоны ошибок
    • 403.html
    • 404.html
    • 500.html
  • vers — содержит проверочные файлы для поисковых систем
  • base.html
  • one_col.html
  • two_col.html
  • main.html

Как видите, вынос шаблонов ошибок в отдельную папку — хорошая идея отделить их от шаблонов страниц (one_col.html, two_col.html, main.html). Чтобы указать django, где искать шаблоны по новому пути, нужно использовать метод curry, например:

# urls.py
from django.views.defaults import server_error, page_not_found, permission_denied

handler403 = curry(permission_denied, template_name='errs/403.html')
handler404 = curry(page_not_found, template_name='errs/404.html')
handler500 = curry(server_error, template_name='errs/500.html')

Замечание: в Django>=1.9 нужно добавить ещё один аргумент exception для handler403 и handler404:

handler403 = curry(permission_denied, exception=Exception('Permission Denied'), template_name='errs/403.html')
handler404 = curry(page_not_found, exception=Exception('Page not Found'), template_name='errs/404.html')

Тестирование своих шаблонов ошибок

Чтобы протестировать шаблоны ошибок, достаточно добавить соответствующие urls в urls.py, например так:

if settings.DEBUG:
    urlpatterns = [
        url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
        url(r'', include('django.contrib.staticfiles.urls')),

        # --- error pages ---
        url(r'^403$', handler403),
        url(r'^404$', handler404),
        url(r'^500$', handler500),
    ] + urlpatterns

Теперь можно переходить по адресу http://localhost:8000/404 и видеть свой кастомный шаблон ошибки. На боевом сайте нам тестовые урлы ошибок не нужны, поэтому мы добавили их в условие if settings.DEBUG:.

Создание своего представления для обработки ошибки

Если хочется изменить стандартное поведение обработки ошибок, то нужно писать своё представление. Например:

# urls.py
handler403 = 'my_app.views.show_403'
handler404 = 'my_app.views.show_404'

# my_app/views.py
# Обработка ошибки 403
from django.core.exceptions import PermissionDenied
def show_403(request):
    # какие-либо действия
    raise PermissionDenied

# Обработка ошибки 404
from django.http.response import Http404
def show_404(request):
    # какие-либо действия
    raise Http404

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

# Обработка ошибки 404
from django.http.response import Http404
def 404(request):
    if request.path.startswith('/project/'):
        return render(request, 'project_not_found.html')  # выдаст страницу, что проекта нет и, к примеру, покажет другие проекты
    if request.path.startswith('/shop/'):
        return render(request, 'product_not_found.html')  # выдаст страницу, что товара нет и, к примеру, покажет другие товары

    raise Http404  # в остальных случаях показать стандартное исключение, которое отрендерит наш шаблон 404.html

Некоторые тонкости

Проверка отдачи шаблона 404

Для проверки отдачи шаблона 404 используйте при значении переменной DEBUG=False в settings.py, иначе вам будет показан трейсбек Django.

Внимание! Если DEBUG=False, то вы должны добавить в ALLOWED_HOSTSsettings.py) допустимые доменные имена, иначе Django будет выдавать ошибку “Bad Request (400)”. На локальной машине добавляется ‘localhost’ (или 127.0.0.1).

# settings.py
ALLOWED_HOSTS = ['localhost', ]

Обратите внимание, что при DEBUG=False статические файлы не будут показываться. Для показа статических файлов нужно собрать статику и запустить сервер с опцией --insecure:

python manage.py collectstatic
python manage.py runserver --insecure

Создание своего представления для обработки 500 ошибки

При использовании стандартного представления обработки 500 ошибки в соответствующий шаблон не передаётся контекст. Сделано так для того, чтобы уменьшить количество возможных других ошибок. Поэтому шаблон должен быть простой подобный этому:

<!DOCTYPE html>
<html>
<head>
    <title>Ошибка на стороне сервера</title>
    <meta name="robots" content="noindex, nofollow">
</head>
<body>
    <p>Извините, но что-то случилось с сайтом.</p>
    <p>В техническую поддержку уже отправлено уведомление.</p>
</body>
</html>

Если будете делать своё представление для 500 ошибки, то следуйте правилам django — не передавайте RequestContext при рендеринге шаблона. Посмотрите как происходит обработка в стандартном представлении django.views.defaults.server_error.

Отображение ошибок без рендеринга шаблонов

from django.http import HttpResponseNotFound 

def test_view_1(request, param):  
  if not param:  # какое-то условие
    return HttpResponseNotFound('<p>Страница не найдена</p>')  

  return render_to_response('test_view_1.html')  


from django.http.response import HttpResponseForbidden
def test_view_2(request, param):
    if not param:
        return HttpResponseForbidden('Доступ запрещён')

    return render_to_response('test_view_2.html')

Надеюсь, статья помогла ответить на возникающие вопросы об обработке ошибок в Django.

Оцените статью

3.9 из 5 (всего 7 оценок)

После нажатия кнопки «Отправить» ваше сообщение будет доставлено мне на почту.

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/django-custom-templates-for-errors/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/django-custom-templates-for-errors/">https://vivazzi.pro/ru/it/django-custom-templates-for-errors/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.

Я пытаюсь автоматизировать тестирование 404 страниц с помощью платформы тестирования Django 1.4.

если я распечатаю 127.0.0.1:8000/something/really/weird/ в адресной строке браузера с запущенным сервером разработки я вижу страницу 404 с правильным статусом «404 не найден» (как показывает firebug).

но если я пытаюсь использовать этот код для проверки:

from django.test import TestCase
class Sample404TestCase(TestCase):
    def test_wrong_uri_returns_404(self):
        response = self.client.get('something/really/weird/')
        self.assertEqual(response.status_code, 404)

тест терпит неудачу с этим выходом:

$./manage.py test main
Creating test database for alias 'default'...
.F
======================================================================
FAIL: test_wrong_uri_returns_404 (main.tests.Sample404TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File ".../main/tests.py", line 12, in test_wrong_uri_returns_404
    self.assertEqual(response.status_code, 404)
*AssertionError: 200 != 404*

----------------------------------------------------------------------
Ran 2 tests in 0.031s

FAILED (failures=1)
Destroying test database for alias 'default'...

Я серьезно удивлен, получив 200 код здесь. Кто-нибудь знает, почему на земле это происходит?

обновление:

здесь лежит urls.py:http://pastebin.com/DikAVa8T
и фактический неудачный тест:

def test_wrong_uri_returns_404(self):
    response = self.client.get('/something/really/weird/')
    self.assertEqual(response.status_code, 404)

все происходит в проекте https://github.com/gbezyuk/django-app-skeleton

2 ответов


проблема в том, что ваш класс ViewFor404 возвращает код состояния 200. Посмотрите на определение TemplateView Джанго:

class TemplateView(TemplateResponseMixin, View):
    """
    A view that renders a template.
    """
    def get_context_data(self, **kwargs):
        return {
            'params': kwargs
        }

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

Так что все ваши класса является render_to_response, который генерирует ‘200’ ответ.

Если вам нужно переопределить обработчик 404, вы должны сделать что-то вроде этого в представлении:

return HttpResponseNotFound('<h1>Page not found</h1>')

(Я не знаю эквивалента в представлениях на основе классов)

или еще лучше, вы можете избежать настройки посмотреть? К настроить отображение 404, вы можете просто создать 404.html-шаблон (в шаблонах/ каталоге вашего сайта), и он будет подхвачен средством просмотра ошибок Django.


попробовать

response = self.client.get('/something/really/weird/') # note the '/' before something

127.0.0.1:8000/something/really/weird/ is /something/really/weird/ в пути относительно корня,не

  • something/really/weird
  • something/really/weird/
  • /something/really/weird

Понравилась статья? Поделить с друзьями:
  • Урок 153 работа над ошибками 2 класс
  • Урок 147 работа над ошибками русский язык 2 класс
  • Уровня значимости и ошибки 1 го рода
  • Уровни ошибок в русском языке
  • Уровень масла пежо 308 ошибка