Sergio Álvarez (xergio)

Escrito 311

Optimización de páginas web

Hoy he recibido toda una lección sobre cómo optimizar el consumo de ancho de banda de una web. Podía esperarme una lección así de cualquiera menos de quien me ha venido, jcea. Siempre tan serio, poco hablador y concreto, parece que hoy le ha dado la neura y ha conseguido reducirme el consumo de esta página en un 75% (más o menos, a ver en los días sucesivos).

Me ha recordado una barbaridad de conceptos que tenía olvidados, y voy a apuntarlos para que esto no vuelva a pasar. Muchas de las cosas que me ha contado las tiene ya apuntadas en su web como ¿Por qué y cómo crear un espacio web "cache friendly"?.

Lo primero que hicimos fue habilitar compresión Gzip en Apache. Yo uso apache2, así que usé el mod_deflate con la siguiente configuración:

<IfModule mod_deflate.c>
    # Insert filter
    SetOutputFilter DEFLATE

    # Netscape 4.x has some problems...
    BrowserMatch ^Mozilla/4 gzip-only-text/html

    # Netscape 4.06-4.08 have some more problems
    BrowserMatch ^Mozilla/4.0[678] no-gzip

    # MSIE masquerades as Netscape, but it is fine
    BrowserMatch bMSI[E] !no-gzip !gzip-only-text/html

    # Don't compress images and files that are already compressed
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    SetEnvIfNoCase Request_URI .(gif|jpeg|jpg|png)$ no-gzip dont-vary

    <IfModule mod_headers.c>
        Header append Vary User-Agent env=!dont-vary
        Header unset Expires
        Header unset Cache-Control
        Header unset Pragma
    </IfModule>
</IfModule>

Esto entre otras cosas lo que hace es comprimir documentos que no sean imágenes o similares, los cuales ya van en parte comprimidos por su formato correspondiente. También me he cargado cabeceras HTTP referentes a la caché de los navegadores para que estos actúen con libertad en ese aspecto. Hay que decir que esto no va del todo bien, pero bueno, al menos los documentos HTML por ejemplo ya ocupan 3/4 partes menos. Mismamente la portada de este blog pesaba unos 16KB y ahora solo son unos 4KB.

Una vez que los navegadores tienen libertad para cachear imágenes y demás, hemos modificado el script que muestra las fotos de este blog para que le diga al navegador la antigüedad del archivo y este pueda cachearla sin problema, evitando así que cada vez se carguen de nuevo las fotos y el consiguiente aumento de ancho de banda. Para ello no tendremos más que enviar la última fecha de modificación de la imágen. Si el navegador la ha cacheado en una visita anterior, al pedir de nuevo la foto enviará la fecha de la foto que él tiene retenida, y si es igual a la que yo tengo no hace falta que la vuelva a cargar, le digo que no la he cambiado y que use la suya:

// obtengo la fecha de modificación
$mtime = filemtime($this->path($tamano));
// si el navegador tiene una cacheada...
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    $ims = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);
    $ims_unix = strtotime($ims);
    //
    // comparo la fecha de la suya con la de la mia
    if ($ims_unix == $mtime) {
        // y si coinciden le digo que nada, que use la suya
        header("HTTP/1.0 304 Not Modified");
        exit;
    }
}
// si no tiene la imágen cacheada le digo la fecha de la mia
header("Last-modified: " . gmdate("D, d M Y H:i:s", $mtime) . " GMT");

Esto me va a ahorrar la carga de muchas imágenes que antes lo hacían de forma innecesaria. Además será más cómodo para los visitantes, porque la primera carga será como siempre, lenta, pero luego irá como un tiro.

Por último he hecho algo similar en los documentos HTML. El resultado de lo que se supone que será la página lo guardo en memoria, genero un identificador único a partir de todo el código, y ese identificador lo mando en una cabecera llamada ETag. Con ese identificador, el navegador me lo devuelve en otra cabecera distinta al volver a pedir la página en otra ocasión, y si ese identificador es igual a la página que le voy a mostrar, le digo que no, que muestre la que tiene él y así no me hace consumir ancho de banda. En cambio si son diferentes ya le mando el código HTML nuevo y que el navegador haga con él lo que quiera, cachearlo, desecharlo, etc.:

// al principio del código pongo...
ob_start();
//
// por aquí html, cófigo php, lo que sea
//
// y al final ya obtengo lo que hay en memoria
$dochtml = ob_get_contents();
ob_end_clean();
//
// genero el identificador
$sha1dochtml = sha1($dochtml);
// y si el que me envia el cliente/navegador es igual al mio
if ($_SERVER['HTTP_IF_NONE_MATCH'] == '"' . $sha1dochtml . '"') {
    // le digo que muestre su documento directamente
    header("HTTP/1.0 304 Not Modified");
    exit;
//
// y sino pues nada, le mando el documento nuevo y el ETag nuevo
} else {
    header('ETag: "' . $sha1dochtml . '"', true);
    echo $dochtml;
}

Bueno, creo que se puede mejorar bastante el texto. jcea me dió permiso para colgar el log de la conversación pero eso ya con más tiempo, porque aunque no los creáis son las 8 de la tarde y yo aun no me he acostado :o (la noche anterior claro). Hoy fijo que no me acuesto tarde ni me despierto a las 3 como siempre :D

Una vez más, gracias jcea, hoy nos has sorprendido a más de uno :)

20 comentarios

 Jabber status guiye comentó:

[Avatar]
  • #1
  • 11-3/21:36
jcea sorprendiendo, yo creía que era el malo malísimo del irc-hispano, insociable, asocial y similares, pero también tiene su pequeño corazoncito. Me compraría un sombrero y me lo quitaba despues, pero carezco de dinero, me lo dejé en un vhost que luego regalaban por memos que tenía ignorados. xDDD

 Jabber status Johnymepeino comentó:

[Avatar]
  • #2
  • 20-3/16:50
Como soy viejo y no uso Apache no me he enterado de nada, pero vosotros convertidlo en standard y así lo tendremos por defecto :)

Un saludo Xergi (o) :D

yo comentó:

  • #3
  • 22-3/21:00
mira este video sergio,esta currao: http://youtube.com/watch?v=49IDp76kjPw

 Jabber status xergio comentó:

[Avatar]
  • #4
  • 23-3/00:21
si, ya lo había visto, gracias :)

(no sé qué tiene que ver con el artículo, pero bueno)

 Jabber status corsaria comentó:

[Avatar]
  • #5
  • 24-3/23:32
Vaya, interesante. Saludos Xergio. ;-)

 Jabber status Daniel Cáceres comentó:

[Avatar]
  • #6
  • 26-3/11:46
Una pregunta de novato... todo esto lo pones en el .htaccess?

 Jabber status xergio comentó:

[Avatar]
  • #7
  • 26-3/13:59
evidentemente no... por ejemplo ahí hay código PHP

JMG comentó:

  • #8
  • 4-4/11:34
He probado lo de cachear el html y funciona perfectamente, pero tengo una duda, si tienes publicidad de google adsense, ¿tambien se queda cacheada o cada vez que recarga la página hace una nueva petición a los servidores de adsense?. En cuanto a los de las imagenes, es mas complicado, creo entender que hay que marcarlas una por una...

Una ultima cosa. Los que no tenemos acceso al archivo de configuración de pache, ¿hay alguna posibilidad de hacer que no se compriman imágenes con httaccess?. Yo uso para comprimir la funcion php: ob_start('ob_gzhandler');

Ciao...

 Jabber status lucio martin jorge comentó:

[Avatar]
  • #9
  • 10-4/17:03
man un fabor pos mandarte el ejemplo de optimizacion de pag web se lo agredesere .... mi correo lmjc11@hotmail.com

 Jabber status xergio comentó:

[Avatar]
  • #10
  • 10-4/18:42
joe, pero no lo tienes ahí todo???

 Jabber status lucio martin jorge comentó:

[Avatar]
  • #11
  • 23-5/17:02
Por fin se recupera password de msn hotmail mobil 539991360 Email lmjc11@hotmail.com

 Jabber status lucio martin jorge comentó:

[Avatar]
  • #12
  • 12-6/17:00
recuperar contraseñas de msn hotmail.com mi CEl 539991360 email lmjc11@hotmail.com

 Jabber status corsaria comentó:

[Avatar]
  • #13
  • 17-2/15:42
Uy!! después de esto te pedirán cómo hacer un huevo revuelto y que les envíes la receta por mail... o_O

Saludetes. :)

 Jabber status xergio comentó:

[Avatar]
  • #14
  • 17-2/18:22
otro post arreglado... :)

 Jabber status Martín comentó:

[Avatar]
  • #15
  • 16-6/09:59
Buen día, yo alojo en un host donde usan este método (Etag) para no consumir tanto ancho de banda, mi consulta es ¿cómo puedo desactivarlo yo?, ¿hay alguna forma por HTACCESS? intente muchas cabezeras como "header("HTTP/1.0 304 Not Modified"); header("Cache-Control: max-age=1, must-revalidate"); // HTTP/1.1 header("Pragma: no-cache");  header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");" también probe <IfModule mod_headers.c>     Header unset Etag </IfModule> en el HTACCESS pero nada, ¿tiene solución esto sin pedirle al hosting que lo saquen?

Anónim@ comentó:

  • #16
  • 13-4/04:41
hfgdhtdh

 Jabber status ju comentó:

[Avatar]
  • #17
  • 13-4/04:41
sfghgfdh

 Jabber status ju comentó:

[Avatar]
  • #18
  • 13-4/04:44
kjhfhjk

dfg comentó:

  • #19
  • 13-4/07:12
hgfsfg

 Jabber status Lorena comentó:

[Avatar]
  • #20
  • 8-5/01:25
Buenas, Tengo una duda: Esto: $mtime = filemtime($this->path($tamano)); ¿De que recoge exactamente la fecha? ¿De las imagenes, del HTML? ¿Donde se ha de colocar?¿En una función?

En mi web tengo funcionando algo similar, tambien usa el bufer, pero en mi caso lo que hace es generar un archivo html que guardo en en servidor, y si vuelven a pedir la página , comprueba si ha caducado y si no, se muestra el HTML guardado comprimido con Gzip, de esta manera reduzco las consultas MySql y el peso del html.

Mi problema es que el consumo mensual es superior a 30Gb porque no consigo hacer que cachee todas las imagenes y el html.

Espero que vuestra aportación me ayude a conseguirlo.

Un saludo y gracias

Deja un comentario

Pulsa en los títulos para ver información sobre cómo comentar.

Autocompletado de nicks

Todos los campos del formulario son opcionales menos el del PIN.

Usa el tabulador para autocompletar los nicks de otros comentaristas.

Si escribes @ y pulsas la tecla tabulador varias veces podrás recorrer la lista de nicks usados

Y si escribes # (almoadilla) y número (Ej.: #5) se substituirá directamente el nick del comentario correspondienmte al pulsar el tabulador.

Tags HTML permitidos

Tags: a, strong, b, em, u, code, cite.

El tag a admite la propiedad href="..." para indicar la dirección.

Los tags también tienen autocompletado (al igual que los nicks). Para usarlos se pone por ejemplo strong + TABULADOR.

Formulario para comentar

Cargando...

Todo el contenido bajo el dominio XERGIO.NET está sujeto a la licencia Creative Commons con las condiciones BY-SA. Web estandarizada en XHTML 1.0, CSS 2, RSS 2 y Atom 1.0.