Как добавить заголовки без кэширования на все 404 страницы, обслуживаемые apache и nginx?

9

Я недавно столкнулся с проблемой после перехода на Cloudflare, и решение состоит в том, чтобы в основном остановить Cloudflare от кэширования 404 ответов.

В нашей многосерверной настройке с балансировкой нагрузки случаются случайные 404, но они быстро исправляются с помощью rsync (через lsyncd). До появления Cloudflare повторный запрос к файлу 404ed очень быстро становился бы 200, поскольку rsync выполняет свою работу.

Однако, поскольку Cloudflare кэширует все данные на основе заголовка кэширования, и ни apache, ни nginx не отправляют заголовок без кэширования в течение 404 с, Cloudflare на некоторое время заканчивает кэширование ответа 404.

Я искал решение, чтобы глобально добавить такой заголовок для 404s в apache и nginx (глобально, для всех размещенных доменов), но до сих пор оставалось пустым.

Кто-нибудь может помочь?

Спасибо.

Артем Руссаковский
источник
Аналогичный вопрос, правда, только для apache (также остается без ответа): serverfault.com/questions/331544/… .
Артем Руссаковский
До сих пор я почти уверен, что вы не можете переопределить заголовки, возвращенные обработчиками 404 по умолчанию в apache и nginx (пожалуйста, докажите, что я не прав!). Мне удалось переопределить обработчик 404 и указать его на файл PHP, который отправляет такие заголовки в apache, но, поскольку nginx не поддерживает PHP в моей настройке, и параметр «expires -1;» на месте 404, похоже, ничего не делал, я все еще не знаю, как это сделать в nginx.
Артем Руссаковский

Ответы:

6

Разве вы не можете обойтись использованием директивы error_page, а затем обработать местоположение отдельно с добавленным заголовком?

например, в Nginx:

    server {
      ...
      error_page 404 /404.html;
      location = /404.html {
        root   /usr/share/nginx/html;
        add_header Cache-Control "no-cache" always;
      }
    }
jimmiw
источник
1
Здесь есть два вопроса, но я пошел в этом направлении. 1. Я не хотел переопределять страницу 404 по умолчанию и должен создавать правила для каждой, listenпоскольку locationне поддерживается внутри httpнапрямую. 2. Что еще более важно, ваш фрагмент на самом деле не работает, потому что add_header применяется только к 20X и 30X ( nginx.org/en/docs/http/ngx_http_headers_module.html ). Однако нам повезло, поскольку с недавно вышедшей версии 1.7.5 вы можете добавить alwaysмодификатор, который будет применять его ко всем кодам ответов. Мне пришлось обновить nginx, но это был хороший удар в зад. Оно работает.
Артем Руссаковский
2
Я обновил свой ответ, возможно, вам следует добавить ответ, показывающий, что вы сделали, чтобы решить вопрос?
Джимми
Похоже, опущение rootработает. Если это будет удалено, это в значительной степени то, что я в итоге сделал для nginx.
Артем Руссаковский
Для apache я решил, что на самом деле хочу использовать пользовательскую страницу, поэтому я сделал это: ErrorDocument 404 /path/to/my/404.php. И затем внутри 404.php я <<php // не кэшировал заголовок 404 («Cache-Control: no-cache, must-revalidate»); // HTTP / 1.1 header («Истекает: сб, 26 июля 1997 г., 05:00:00 по Гринвичу»); // Свидание в прошлом?>
Артем Руссаковский
Я отмечаю ваш ответ как принятый. Если кто-то захочет предоставить более общий ответ apache позже или nginx, который работает глобально, а не на основе server, они могут получить голосование.
Артем Руссаковский
5

Вы также можете сделать это так:

map $status $cache_header {
    default <for_other_codes>;
    404     "no-cache";
}


server {

    [ ... ]

    add_header "Cache-Control" $cache_header always;

}
Ксавье Лукас
источник
Умная. Я, вероятно, собираюсь пойти с другим решением, так как оно уже работает и не требует, чтобы заголовок Cache-Control по умолчанию указывался каждый раз, но это было некоторое размышление вне коробки.
Артем Руссаковский
После этого пропущена точка с запятой, 404 "no-cache"но глупое ограничение минимального 6-символьного редактирования в stackexchange не позволяет мне это исправить. Понятно, что это не очень хорошее ограничение для сайта, посвященного кодированию и настройкам ...
nh2
3

В Apache 2.4 вы можете попробовать что-то вроде:

FileETag None
<IfModule mod_headers.c>
    Header always unset ETag "expr=%{REQUEST_STATUS} == 404"
    Header always set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" "expr=%{REQUEST_STATUS} == 404"
    Header always set Pragma "no-cache" "expr=%{REQUEST_STATUS} == 404"
    Header always set Expires "Wed, 11 Jan 1984 05:00:00 GMT" "expr=%{REQUEST_STATUS} == 404"
</IfModule>

Это alwaysважно, потому что это:

Вы добавляете заголовок к локально сгенерированному неуспешному (не 2xx) ответу, такому как перенаправление, и в этом случае в окончательном ответе используется только таблица, соответствующая всегда.

Вы сказали, что все 404-е, но для полной справки, конечно, может иметь смысл обернуть это в <FilesMatch>или <LocationMatch>ограничить область.

Я считаю, что это новая возможность в Apache 2.4, так как использование exprусловных выражений отсутствует в версии 2.2 документации mod_headers.

curl -I [foo] тест без этого конфига:

HTTP/1.1 404 Not Found
Date: Thu, 24 May 2018 17:44:29 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1

curl -I [foo] проверить с этим конфигом:

HTTP/1.1 404 Not Found
Date: Thu, 24 May 2018 17:44:42 GMT
Server: Apache/2.4.18 (Ubuntu)
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Content-Type: text/html; charset=iso-8859-1

Источники:

http://httpd.apache.org/docs/current/mod/mod_headers.html

cayleaf
источник
0

мои пять центов по этому вопросу -

в нашем PHP-проекте у нас мало 404 страниц, поэтому я решил сделать это на уровне PHP с помощью функций header () PHP

Ник
источник