2010-01-04 6 views
10

Tengo contenido dinámico almacenable en caché hecho en PHP 5.1.0+. Ya envío los encabezados correctos (incluidos Last-Modified y ETag) a los clientes.Responder HTTP_IF_MODIFIED_SINCE y HTTP_IF_NONE_MATCH en PHP

Ahora quiero que mi script pueda contestar $_SERVER['HTTP_IF_MODIFIED_SINCE'] y $_SERVER['HTTP_IF_NONE_MATCH'] cuando esté presente. Cuando las condiciones coinciden, quiero responder un HTTP 304 "Not Modified" a los clientes.

¿Cuáles son las condiciones correctas? ¿Cuándo emito exactamente un 304 en lugar de todo el contenido?

La respuesta aceptada en cuestión How to know when to send a 304 Not Modified response parece emitir esto correctamente, pero tengo momentos difíciles al puerto que el código de PHP 5.

Gracias!

Respuesta

27

siempre he utilizado:

function caching_headers ($file, $timestamp) { 
    $gmt_mtime = gmdate('r', $timestamp); 
    header('ETag: "'.md5($timestamp.$file).'"'); 
    header('Last-Modified: '.$gmt_mtime); 
    header('Cache-Control: public'); 

    if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) { 
     if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) { 
      header('HTTP/1.1 304 Not Modified'); 
      exit(); 
     } 
    } 
} 

No recuerdo si lo he escrito o tengo desde otro lugar ...

estoy usando normalmente en la parte superior de un archivo de esta forma:

caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME'])); 
+1

¡Gran función! ¡De Verdad! ¡Salvó mi día! – Industrial

+4

Función agradable ¡Rico! Un poco más legible: 'caching_headers (__FILE__, filemtime (__ FILE __));'. – Julian

+1

¡Muy útil! Intenté esto pero realizar varias solicitudes da como resultado un 200 y un 304. Mover el "Último Modificado" y el "Control de Caché" después de la definición de "ETag" lo corrige. –

0

Si el cliente ha realizado una petición GET condicional y el acceso está permitido , pero el documento no ha sido modificado , el servidor debe responder con este código de estado. La respuesta 304 NO DEBE contener un cuerpo de mensaje , y por lo tanto siempre es terminado por la primera línea vacía después de los campos de encabezado.

De - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5

lo tanto, si se envía un 304 no envían el cuerpo.

+0

Lo sé y mi pregunta no es sobre esto ... Mi pregunta es sobre ¿CUÁNDO envío un 304 ... – AlexV

+0

¿Es decir, en qué punto del script php? – user151841

+0

Lo siento, tengo que reducir la velocidad, =] –

3

La respuesta a la que hace referencia parece contener todo lo que necesita. Para resumir:

  • generar su propia ETag y la cabecera Last-Modified, igual que si sería el envío de todo el cuerpo
  • mirada en el If-Modified-Since encabezado enviado al cliente, si su propia última- modificado es más antiguo o el mismo envía el 304
  • mira el encabezado If-None-Match del cliente, si coincide con tu ETag envía el 304
  • si llegas a este lugar, los encabezados no coinciden, envía cuerpo completo y nuevos encabezados ETag/Last-Modified
1

Aquí hay un fragmento de mi función render_file().

$last_modified = filemtime($filename); 
if ($last_modified === false) { 
    throw new Exception('Modify date unknown'); 
} 
if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) { 
    $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'])); 
    if ($if_modified_since >= $last_modified) { // Is the Cached version the most recent? 
    header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified'); 
    exit(); 
    } 
} 
header('Last-Modified: '.date('r', $last_modified)); // tz should be GMT according to specs but also works with other tzs 

// other headers and contents go here 
+0

¿Y qué pasa con HTTP_IF_NONE_MATCH? ¿Dónde debería colocarse en su fragmento? – AlexV

+1

La fecha de modificación fue la validación suficiente para mí, el cálculo de un Etag (suma de comprobación para los contenidos md5/sha1) genera un poco de sobrecarga del servidor. Sin embargo, los etags son menos propensos a errores. Si la corrección del contenido es importante, primero consulte el IF_NONE_MATCH. Si el IF_NONE_MATCH no está configurado, entonces verifique el IF_MODIFIED_SINCE. No verifique IF_MODIFIED_SINCE si el etag no coincide. ¡Porque sabes que la memoria caché del navegador no es válida! Simplemente envíe el encabezado 304 y salga() –

-3

¿Por qué?

Después de haber investigado mucho sobre el tema encontré que las solicitudes condicionales en realidad ralentizan un sitio. Hay ciertos escenarios en los que no es el caso, pero el mapeo de los patrones de uso general en general da como resultado un rendimiento menor y un almacenamiento en caché menos efectivo.

C.

+0

¿Por qué desaceleraría un sitio? Ni siquiera puedo imaginar cómo lo ralentizaría (si envía los encabezados de caché adecuados) ... – AlexV

+1

La respuesta corta a esa pregunta es de aproximadamente 5 páginas de texto y gráficos. Sigo pensando en ponerlo en internet en alguna parte ... mire este espacio. – symcbean

+0

Sería interesante ver que :) – AlexV

0

This article responderá a todas sus preguntas sobre el almacenamiento en caché

He encontrado que la adición de

RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}] 
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}] 

Al final de mi archivo htaccess (debajo de todas las reescrituras) funcionó.

Cuestiones relacionadas