2008-08-07 8 views
9

Estoy escribiendo un método de manejo de recursos donde controlo el acceso a varios archivos, y me gustaría poder hacer uso de la memoria caché del navegador. Mi pregunta es doble:Cómo saber cuándo enviar una respuesta 304 No modificada

  1. Cuáles son las cabeceras HTTP definitivas que tengo que comprobar con el fin de saber con certeza si debería enviar una respuesta 304, y lo que estoy buscando cuando las hago compruebo ?

  2. Además, ¿hay algún encabezado que deba enviar cuando inicialmente envío el archivo (como 'Last-Modified') como respuesta 200?

Algunos psuedo-code probablemente sean la respuesta más útil.


¿Qué pasa con el encabezado de caché-control? ¿Pueden los diversos valores posibles de eso afectar lo que le envías al cliente (es decir, max-age) o solo debe modificarse, ya que se debe obedecer?

+1

Me gustaría agregar entonces al enviar una respuesta 304, solo debe enviar el encabezado y no el contenido. – GateKiller

Respuesta

8

Así es cómo lo implementé. El código ha estado funcionando por un poco más de un año y con múltiples navegadores, así que creo que es bastante confiable. Esto se basa en RFC 2616 y al observar qué y cuándo estaban enviando los distintos navegadores.

Aquí está el pseudocódigo:

 
server_etag = gen_etag_for_this_file(myfile) 
etag_from_browser = get_header("Etag") 

if etag_from_browser does not exist: 
    etag_from_browser = get_header("If-None-Match") 
if the browser has quoted the etag: 
    strip the quotes (e.g. "foo" --> foo) 

set server_etag into http header 

if etag_from_browser matches server_etag 
    send 304 return code to browser 

He aquí un fragmento de mi lógica del servidor que se encarga de esto.

 
/* the client should set either Etag or If-None-Match */ 
/* some clients quote the parm, strip quotes if so */ 
mketag(etag, &sb); 

etagin = apr_table_get(r->headers_in, "Etag"); 
if (etagin == NULL) 
    etagin = apr_table_get(r->headers_in, "If-None-Match"); 
if (etag != NULL && etag[0] == '"') { 
    int sl; 
    sl = strlen(etag); 
    memmove(etag, etag+1, sl+1); 
    etag[sl-2] = 0; 
    logit(2,"etag=:%s:",etag); 
} 
... 
apr_table_add(r->headers_out, "ETag", etag); 
... 
if (etagin != NULL && strcmp(etagin, etag) == 0) { 
    /* if the etag matches, we return a 304 */ 
    rc = HTTP_NOT_MODIFIED; 
} 

Si quieres algo de ayuda con el poste de generación etag otra pregunta y voy a sacar algo de código que hace eso también. HTH!

+0

¿Realmente ha encontrado clientes que envían un encabezado 'ETag' en la solicitud? Se supone que solo debe usarse en las respuestas. También siempre debe ser citado de acuerdo con la especificación. –

+0

Matt, el cliente devuelve el etag que ha recibido anteriormente, por lo que el servidor puede decidir si HTTP_NOT_MODIFIED es una respuesta adecuada. Mi trabajo principal en el momento en que hice esto fue con Firefox y Safari; ambos incluirían el etag almacenado si una solicitud previa para el recurso dado le hubiera dado un etag al cliente. Consulte "Uso típico" aquí: http://en.wikipedia.org/wiki/HTTP_ETag –

+0

El cliente incluye sus etag (s) en los encabezados 'If-None-Match' /' If-Match'. Nunca he visto un UA enviar un encabezado 'ETag:" ... "' en una solicitud, ¿o sí? –

3

Debe enviar un 304 si el cliente ha declarado explícitamente que ya puede tener la página en su caché. Esto se denomina GET condicional, que debe incluir el encabezado if-modified-since en la solicitud.

Básicamente, este encabezado de solicitud contiene una fecha desde la cual el cliente dice tener una copia en caché. Debe verificar si el contenido ha cambiado después de esta fecha y enviar un 304 si no lo ha hecho.

Ver http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 para la sección relacionada en la RFC.

1

respecto Cache-Control:

Usted no debería tener que preocuparse por el cache-control al servir a cabo, aparte de ajustarlo a un valor razonable. Básicamente le dice al navegador y a otras entidades en sentido descendente (como un proxy) el tiempo máximo que debe transcurrir antes de que se agote el tiempo de caché.

4

A 304 La respuesta no modificada puede ser el resultado de una solicitud GET o HEAD con un encabezado If-Modified-Since ("IMS") o un encabezado If-Not-Match ("INM").

Para decidir qué hacer cuando recibe estos encabezados, imagine que está manejando la solicitud GET sin estos encabezados condicionales. Determine cuáles serían los valores de su ETag y encabezados Last-Modified en esa respuesta y úselos para tomar la decisión. Es de esperar que hayas construido tu sistema de modo que determinar esto sea menos costoso que construir la respuesta completa.

Si hay una INM y el valor de esa cabecera es el mismo que el valor que colocar en la ETag, a continuación, responder con 304.

Si hay un IMS y el valor de la fecha en la que es cabecera más tarde que la que colocaría en Last-Modified, responda con 304.

De lo contrario, proceda como si la solicitud no contuviera esos encabezados.

Para un acercamiento de menor esfuerzo a la parte 2 de su pregunta, descubra cuál de los encabezados (Caduca, ETag y Última modificación) puede producir fácil y correctamente en su aplicación web.

Para material de lectura sugerido:

http://www.w3.org/Protocols/rfc2616/rfc2616.html

http://www.mnot.net/cache_docs/

2

También están manejando en caché, pero garantizados, recursos. Si envía/genera un encabezado de ETAg (que RFC 2616 sección 13.3 le recomienda que DEBERÍA), entonces el cliente DEBE usarlo en una solicitud condicional (normalmente en un encabezado If-None-Match - HTTP_IF_NONE_MATCH -). Si envía un encabezado Last-Modified (DE NUEVO, DEBERÍA), debe verificar el encabezado If-Modified-Since-HTTP_IF_MODIFIED_SINCE -. Si envía ambos, entonces el cliente DEBE enviar ambos, pero DEBE enviar el ETag. También tenga en cuenta que la validez se define simplemente como la comprobación de los encabezados condicionales para la igualdad estricta frente a los que enviaría. Además, solo se usará un validador fuerte (como un ETag) para solicitudes a distancia (donde solo se solicita parte de un recurso).

En la práctica, ya que los recursos que estamos protegiendo son bastante estática, y un segundo de tiempo de retraso es aceptable, estamos haciendo lo siguiente:

  1. Compruebe si el usuario está autorizado para acceder a la recurso solicitado

    Si no lo están, redirigirlos o enviar una respuesta 4xx según corresponda. Generaremos 404 respuestas a solicitudes que parecen intentos de pirateo o intentos evidentes de realizar una ejecución final de seguridad.

  2. comparar el If-Modified-Since encabezado a la cabecera Last-Modified enviaríamos (véase más adelante) por la igualdad estricta

    Si coinciden, enviar un procesamiento de la respuesta y la página de salida 304 Not Modified

  3. Crear una cabecera Last-Modified utilizando el tiempo de modificación del recurso solicitado

    buscar el formato HTTP Fecha en la RFC 2616

  4. Enviar el contenido de la cabecera y de los recursos junto con una adecuada Content-Type

Decidimos evitar la cabecera ETag ya que es una exageración para nuestros propósitos. Supongo que también podríamos usar el sello de fecha y hora como ETag. Si pasamos a un verdadero sistema ETag, probablemente almacenaremos hashes computados para los recursos y los utilizaremos como ETags.

Si sus recursos se generan dinámicamente, por ejemplo, el contenido de la base de datos, entonces ETags puede ser mejor para sus necesidades, ya que son solo texto para rellenar como mejor le parezca.

Cuestiones relacionadas