Как настроить страницу ошибки в nginx?

10

Я сейчас настраиваю обработку nginx некоторых страниц ошибок и других медиа-файлов «по умолчанию» (таких как favicon.ico и robots.txt), и столкнулся с небольшой проблемой, заставляющей вещи работать так, как я хочу, для определенных страниц ошибок ,

По сути, я пытаюсь обслуживать определенные файлы для сервера в корневом каталоге этого сервера, например /var/www/someserver.com/robots.txt. Если этот файл не существует, я хочу, чтобы nginx перешел в «default», то есть /var/www/default/robots.txt. Это основная суть того, как я (успешно) настроил:

server {
    ...
    root /var/www/someserver.com;

    location ~* ^/(robots\.txt)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Это прекрасно работает.

Я пытаюсь сделать то же самое для страниц с ошибками, но я не могу этого сделать:

server {
    ...
    root /var/www/someserver.com;

    error_page 404   /404.html;

    location ~* ^/(404\.html)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Обратите внимание, что это «работает» в том смысле, что если вы посещаете someserver.com/404.html, сначала он попытается загрузить /var/www/someserver.com/404.html, а затем вернуться к / var / www / default /404.html если это не найдено. Однако, если вы посетите someserver.com/blahblah, страница 404 отображается только в том случае, если она установлена ​​в /var/www/someserver.com/. Он не возвращается к каталогу по умолчанию, если этот файл не существует.

Во всяком случае, вы можете, вероятно, то, что я пытался достичь (поэтому я включил первый рабочий пример).

Любые идеи?

Редактировать:

Основываясь на ответе Мартина Ф., вот что я закончил:

# Doesn't work when error page is returned on a POST request
server {
    ...
    root /var/www/someserver.com;

    error_page  404         = @notfound;
    error_page  500 502 504 = @server_error;
    error_page  503         = @maintenance;

    location @notfound {
        try_files /404.html /../default/404.html =404;
    }

    location @server_error {
        try_files /500.html /../default/500.html =500;
    }

    location @maintenance {
        try_files /503.html /../default/503.html =503;
    }
}

Это работает потрясающе. Фактический блок error_pages и местоположений выше находится в файле server_defaults.conf, который включается в каждый виртуальный хост, поэтому я не жестко прописал путь к каждому местоположению и использовал относительный путь для значений по умолчанию.

Изменить 2:

У этого подхода есть проблема. Если вы отправляете POST по URL, который возвращает ошибку, метод запроса POST отправляется с попытками try_files. Это (для меня) приводит к ошибке 405 Not Allowed, потому что nginx, по сути, пытается POST, например, /default/500.html вместо того, чтобы просто получить эту страницу.

Изменить 3:

Я опубликовал решение, которое работает намного ближе к моей первоначальной идее.

Джим Д
источник

Ответы:

10

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

server {
    ...

    root /var/www/someserver.com/;

    error_page 400 404      /404.html;
    error_page 500 502 504  /500.html;
    error_page 503          /503.html;

    recursive_error_pages   on;

    location ~* ^/(404\.html|500\.html|503\.html)$ {
        log_not_found off;
        error_page 404 = @default;
    }

    location @default {
        log_not_found on;
        root /var/www/default;
    }
}

Я включил другие типы ошибок, которые не были частью моего первоначального вопроса, потому что это привело к тому, что у меня возникли трудности с подходом Мартина Ф., который в остальном был превосходным. log_not_foundДиректива только гарантирует , что я не получаю в моем 404 - журнале , когда страница ошибки не найден в исходном корне.

Джим Д
источник
Это работает отлично (особенно в отношении комбинации 404 / POST), но, похоже, глотает код ошибки HTTP и отправляет 200 ... У вас такое же поведение, как и у меня?
Октябрь
2
Вы можете удалить log_not_found off;и добавить internal;вместо этого.
Аликс Аксель
Проблема, которую вы заметили с помощью запроса POST, приводящего к ошибке, заключается в странном поведении nginx, см. Trac.nginx.org/nginx/ticket/824
Robo
5

try_files это путь сюда. Следующая конфигурация должна работать, но я не проверял ее на синтаксические ошибки.

server {
    ...
    root /var/www;

    location / {
        try_files /someserver.com$uri /default$uri /someserver.com$uri/ /default$uri/ @notfound;
    }

    location @notfound {
       try_files /someserver/404.html /default/404.html =404; # =404 should make it use the nginx-default 404 page.
    }
}
Мартин Фьордвальд
источник
Да, это именно то, что мне было нужно. Я пытался использовать try_files, но ваш ответ привел меня к пониманию, что мне нужно создать специальное внутреннее местоположение для него. Я отредактировал свой ответ, чтобы показать работающую для меня конфигурацию, в которой есть несколько настроек, которые вы предложили.
Джим Д
Смотрите мое редактирование 2 выше. Из того, что я могу сказать, это предложение не работает с запросами POST. Поскольку try_files использует метод запроса исходного запроса, вы получите 405 Not Allowed response.
Джим Д
@JimD: Ну, вы точно не используете этот подход, вы используете модифицированный. Это работает для меня. Попробуйте обновить бинарный файл Nginx, если он старше 0.8.x
Мартин Фьордвальд,
Ну, проблема в том, что я использую это больше, чем просто 404, поэтому я должен сделать error_page -> location -> try_files вместо location -> try_files -> location -> try_files, как вы. Однако я использую двоичный файл 0.7.x из пакета, поэтому я постараюсь собрать его из исходного кода и посмотреть, решит ли он это.
Джим Д
2

К сожалению, я опоздал с ответом на пару лет, но я подумал, что он может помочь будущим поисковикам. Моя установленная версия Nginx - 1.2.4, и я создал следующий фрагмент конфигурации:

server {

server_name www.example.com
root /var/www/example


## Errors -> Locations
error_page   400 /400.html;
error_page   403 /403.html;
error_page   404 /404.html;
error_page   500 502 503 504 /50x.html;

## Locations -> Fallback
location = /400.html {
    try_files /400.html @error;
    internal;
}
location = /403.html {
    try_files /403.html @error;
    internal;
}
location = /404.html {
    try_files /404.html @error;
    internal;
}
location = /50x.html {
    try_files /50x.html @error;
    internal;
}

## Fallback Directory
location @error {
    root /var/www/error;
}

}
Дж. М. Беккер
источник
1
Хорошее использование internal.
Клинт Пахл,
0

Я обнаружил, что крайне важно включить "proxy_intercept_errors on;" в любом блоке местоположения, где также была включена error_page.

Без этой настройки блок местоположения будет перехватывать коды ошибок, возвращаемые из восходящего потока.

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors

zayquan
источник