web-dev-qa-db-fra.com

CloudFlare n'envoie pas les en-têtes If-Modified-Since

J'essaie de réduire la charge de mon serveur en fournissant des réponses 304 Not Modified pour le contenu, le cas échéant. CloudFlare est mon intermédiaire, donc ils devraient envoyer des en-têtes If-Modified-Since chaque fois qu'une page en cache a expiré, n'est-ce pas?

Je reçois ces réponses, côté client:

  • CF-Cache-Status: MISS au chargement de la première page
  • CF-Cache-Status: Hit à la page se recharge pendant 20 secondes
  • CF-Cache-Status: EXPIRED à la page recharger après 20 secondes

La demande expirée est transmise à mon serveur, mais n'inclut pas d'en-tête If-Modified-Since. Comment puis-je le faire fonctionner?

<?php
$now = time();
header( "ETag: W/\"$now\"" );
header( 'Expires: '.gmdate('D, d M Y H:i:s \G\M\T', $now + 20) );

header( 'Last-Modified: '.time() );
header( 'Cache-Control: public, max-age=20' );

print('<pre>');
print_r($_SERVER);
print('</pre>');

UPDATE: Voici le code de travail

<?php

if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    // $date = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
    header("HTTP/1.1 304 Not Modified");
    exit();
}

$format = 'D, d M Y H:i:s \G\M\T';
$now = time();

$date = gmdate($format, $now);
header('Date: '.$date);
header('Last-Modified: '.$date);

$date = gmdate($format, $now+30);
header('Expires: '.$date);

header('Cache-Control: public, max-age=30');

print('<pre>'); 
print_r($_SERVER); 
print('</pre>');
3
skibulk

D'après ma compréhension et mon expérience, il me semble que vous avez peut-être mal compris le fonctionnement de la mise en cache CDN:

  • D'après l'exemple que vous avez donné, le CDN ne demanderait pas à votre serveur Web quand le fichier a été modifié pour la dernière fois, car vous lui avez déjà dit que le fichier avait expiré et qu'il fallait donc le récupérer de toute façon.

  • Les navigateurs Web n’enverront un en-tête If-Modified-Since que si la page/ressource a déjà été mise en cache par le navigateur Web et est accompagnée d’un en-tête Last-Modified lors de la première demande.

  • Si vous envoyez un en-tête E-Tag comme dans votre exemple, sa gestion n'est pas uniforme d'un navigateur à l'autre et vous pouvez vous retrouver avec un en-tête If-None-Match dans la requête suivante du navigateur au lieu d'un If-Modified-Since.

Cependant, les CDN ne se comportent généralement pas de la même manière que les navigateurs Web, ils ressemblent parfois plus à des serveurs proxy ou à des accélérateurs Web:

  • Si une page mise en cache par CDN a expiré, le CDN récupérera simplement une nouvelle copie du serveur Web à la prochaine demande d'un navigateur Web, mettra à jour la copie mise en cache par CDN et renverra la ressource au navigateur Web dans le répertoire. Réponse HTTP. Normalement, aucun en-tête If-Modified-Since n'atteint votre serveur Web, bien que mes tests aient révélé que CloudFlare continue de générer cet en-tête.

  • Pour réduire la charge de votre serveur, activez le CDN pour fournir un niveau de mise en cache supérieur à celui déjà utilisé par les navigateurs Web, à l'aide de la directive s-maxage. Semblable à la directive max-age sur votre en-tête Cache-Control, toutefois, celui-ci sera observé par les CDN (et les services similaires) en priorité par rapport à tout autre en-tête, tandis que le max-age sera observé par le clients de navigateur Web.

    header( 'Cache-Control: public, max-age=20, s-maxage=60' );

    Si vous utilisez cet en-tête, la première demande d'un navigateur Web sera un CDN MISS mais sera alors mise en cache à la fois sur le navigateur Web et sur le CDN. Après les 20 premières secondes, la copie en cache du navigateur Web expirera. Si la page est ensuite rechargée, le CDN: HIT restaure pendant 40 secondes supplémentaires, renvoyant une copie de CDN-cache au navigateur Web dans la réponse HTTP. Soixante secondes après la première demande, le cache CDN a expiré et une demande ultérieure sera un CDN EXPIRÉ mais sera traité de la même manière qu'un CDN MISS prenant une nouvelle copie de votre serveur Web, ainsi la séquence de boucle continuerait.

    Un en-tête plus prêt à la production, pour la mise en cache du navigateur Web sur une heure et la mise en cache CDN de 6 heures, pourrait ressembler à ceci:

    header( 'Cache-Control: public, max-age=3600, s-maxage=21600' );

    Si vous avez besoin de publier une mise à jour plus rapidement que l'expiration du CDN après 6 heures, vous pouvez toujours demander au CDN d'utiliser un nouveau cache à partir de son panneau de commande Web. Avec cet en-tête, chaque ressource ne serait récupérée que 4 fois par jour sur votre serveur Web, tandis que le CDN gère la majeure partie du trafic Web.


Édité le 11-Nov-2014 @ 12:45 pm UTC-0:

De plus, votre code PHP peut avoir des conséquences sur son bon fonctionnement - vos ETag et Expires = Les lignes d'en-tête de code lorsque je les teste produisent les en-têtes suivants:

ETag: W/""
Expires: Thu, 01 Jan 1970 00:00:20 GMT

Essayez peut-être plutôt ces lignes dans votre test afin que vous puissiez également voir les en-têtes que vous avez envoyés:

<?php
$iClientCacheSecs = 20;
$iProxyCacheSecs = 60;
$dtNow = time();
$dtExpires = strtotime( sprintf( '+%s seconds', $iClientCacheSecs ));
$aHeaders = array();
$aHeaders[] = 'ETag: ' . $dtNow;
$aHeaders[] = 'Expires: ' . date( 'r', $dtExpires );
$aHeaders[] = 'Last-Modified: ' . date( 'r', $dtNow );
$aHeaders[] = sprintf( 'Cache-Control: public, max-age=%s, s-maxage=%s',
  $iClientCacheSecs, $iProxyCacheSecs );
foreach( $aHeaders as $sHeader ) header( $sHeader );
echo( 'Now: ' . date( 'r', $dtNow ) . '<br />' );
foreach( $aHeaders as $sHeader ) echo( $sHeader . '<br />' );
echo( '<hr />' );
foreach( $_SERVER as $sParam => $sValue ) {
  if(( strpos( $sParam, 'HTTP_CF' )) !== false ) 
    echo( $sParam . ': ' . $sValue . '<br />' );
  if(( strpos( $sParam, 'HTTP_IF' )) !== false ) 
    echo( $sParam . ': ' . $sValue . '<br />' );
}
3
richhallstoke

Gardez à l'esprit qu'un en-tête 304 non modifié nécessite toujours une requête adressée à votre serveur.

Vous ne voudrez pas envoyer d’en-têtes 304 non modifiés, mais vous souhaitez plutôt envoyer un en-tête d’expiration du cache afin que le navigateur n’essaye même plus de demander les ressources. Cela ne concerne évidemment que les ressources statiques (images, scripts, etc.).

D'après mon expérience, CloudFlare n'envoie que les en-têtes Last-Modified pour les ressources statiques.

Vous voudrez peut-être consulter les URL des pages de CloudFlare et attribuer à vos pages (pas des images, des scripts, etc.) une valeur de mise en cache personnalisée autre que celle par défaut?

0
Emil Rasmussen