Comment ajouter des en-têtes sans cache aux 404 pages servies par apache et nginx?

9

J'ai récemment rencontré un problème après être passé à Cloudflare, et la solution consiste essentiellement à empêcher Cloudflare de mettre en cache les réponses 404.

Dans notre configuration multi-serveurs à charge équilibrée, des 404 occasionnels se produisent, mais ils sont rapidement corrigés par rsync (via lsyncd). Avant Cloudflare, une nouvelle demande au fichier 404ed deviendrait très rapidement 200 alors que rsync fait son travail.

Cependant, puisque Cloudflare met en cache toutes les données en fonction de l'en-tête de mise en cache, et ni apache ni nginx n'envoient un en-tête sans cache pour les 404, Cloudflare finit par mettre en cache la réponse 404 pendant un certain temps.

J'ai cherché une solution pour ajouter globalement un tel en-tête pour 404s à la fois dans apache et nginx (globalement, pour tous les domaines hébergés), mais jusqu'à présent, nous sommes vides.

Quelqu'un peut-il aider?

Je vous remercie.

Artem Russakovskii
la source
Question similaire, mais uniquement pour apache (toujours sans réponse): serverfault.com/questions/331544/… .
Artem Russakovskii
Jusqu'à présent, je suis presque sûr que vous ne pouvez pas remplacer les en-têtes renvoyés par défaut par 404 gestionnaires dans Apache et Nginx (veuillez me prouver le contraire!). J'ai pu remplacer le gestionnaire 404 et le pointer vers un fichier PHP qui envoie de tels en-têtes dans apache, mais comme nginx n'a pas de support PHP sur ma configuration, et le paramètre "expires -1;" sur l'emplacement 404 ne semblait pas vraiment faire quoi que ce soit, je ne sais toujours pas comment faire cela dans nginx.
Artem Russakovskii

Réponses:

6

Vous ne pouvez pas vous en tirer en utilisant une directive error_page, puis gérer l'emplacement séparément avec l'en-tête ajouté?

par exemple dans Nginx:

    server {
      ...
      error_page 404 /404.html;
      location = /404.html {
        root   /usr/share/nginx/html;
        add_header Cache-Control "no-cache" always;
      }
    }
jimmiw
la source
1
Il y a deux problèmes ici, mais c'est dans cette direction que je suis allé. 1. Je ne voulais pas remplacer la page 404 par défaut et avoir à créer des règles dans tous les cas, listencar elle locationn'est pas prise en charge httpdirectement à l' intérieur . 2. Plus important encore, votre extrait de code ne fonctionne pas car add_header s'applique uniquement aux 20X et 30X ( nginx.org/en/docs/http/ngx_http_headers_module.html ). Cependant, nous avons de la chance, car depuis la version 1.7.5 récemment publiée, vous pouvez maintenant ajouter un alwaysmodificateur qui l'appliquera à tous les codes de réponse. J'ai dû mettre à niveau nginx mais c'était un bon coup de pied dans le cul. Ça marche.
Artem Russakovskii
2
J'ai mis à jour ma réponse, vous devriez peut-être ajouter une réponse montrant ce que vous avez fait pour résoudre la question?
jimmiw
On dirait aussi que l'on omet des rootœuvres. Si cela est supprimé, c'est à peu près ce que j'ai fini par faire pour nginx.
Artem Russakovskii
Pour apache, j'ai décidé que je voulais réellement utiliser une page personnalisée, alors j'ai fait ceci: ErrorDocument 404 /path/to/my/404.php. Et puis à l'intérieur du 404.php, j'ai fait <? Php // ne pas mettre en cache l'en-tête 404 ("Cache-Control: no-cache, must-revalidate"); // en-tête HTTP / 1.1 ("Expire: sam., 26 juil. 1997 05:00:00 GMT"); // Date dans le passé?>
Artem Russakovskii
Je marque votre réponse comme acceptée. Si quelqu'un veut fournir une réponse apache plus générique plus tard, ou une réponse nginx qui fonctionne globalement plutôt que par server, il peut obtenir un vote positif.
Artem Russakovskii
5

Vous pouvez aussi le faire de cette façon:

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


server {

    [ ... ]

    add_header "Cache-Control" $cache_header always;

}
Xavier Lucas
la source
Intelligent. Je vais probablement aller avec l'autre solution, car elle fonctionne déjà et ne nécessite pas un en-tête Cache-Control par défaut à spécifier à chaque fois, mais c'était une réflexion hors des sentiers battus.
Artem Russakovskii
Il manque un point-virgule après, 404 "no-cache"mais la stupide restriction de modification de 6 caractères minimum de stackexchange m'empêche de le corriger. Ce n'est clairement pas une bonne restriction pour un site qui se
concentre
3

Dans apache 2.4, vous pouvez essayer quelque chose comme:

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>

Le alwaysest important car il s'agit d'un:

Vous ajoutez un en-tête à une réponse non réussie (non-2xx) générée localement, telle qu'une redirection, auquel cas seule la table correspondant à toujours est utilisée dans la réponse finale.

Vous avez dit tous les 404, mais pour référence complète, bien sûr, il pourrait être judicieux d'envelopper cela dans un <FilesMatch>ou <LocationMatch>de limiter la portée.

Je pense que c'est une nouvelle capacité dans Apache 2.4 car l'utilisation des exprconditions n'est pas la version 2.2 de la documentation de mod_headers.

curl -I [foo] tester sans cette config:

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] tester avec cette config:

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

Sources:

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

cayleaf
la source
0

mes cinq cents sur la question -

dans notre projet PHP, nous avons quelques 404 pages, donc je décide de le faire au niveau PHP en utilisant les fonctions PHP header ()

pseudo
la source