Habilitando e configurando Cache no Apache (mod_expires)

Olá a todos, no nosso último post, ensinamos como configurar a compressão da resposta do servidor aos usuários, diminuindo bastante o conteúdo de textos, como html, css e javascript. Desta vez o post será para ensinarmos o melhor jeito de se implementar o gerenciamento de cache, fazendo com que os navegadores guardem certos arquivos por uma data especificada pelo servidor, evitando assim um enorme tráfego de rede desnecessário e aumentando muito a velocidade de carregamento da página.

Aproveitar a funcionalidade de cache dos navegadores consiste em definir uma data de validade nos cabeçalhos HTTP para recursos estáticos, instruindo o navegador a carregar os recursos baixados anteriormente a partir do disco local, não através da rede.

Todo administrador de redes, sabe que a tendência é que os sites sejam cada vez mais dinâmicos e ricos em conteúdo, mas toda essa interatividade e riqueza de conteúdo tem um preço, alto tráfego de rede. Quando alguém acessa o seu site, diversos arquivos são baixados, como textos, imagens, css, javascripts. Para impedir todos esses downloads novamente é que surge a necessidade de se gerenciar o cache dos usuários.

Indice

  • O que é cache de navegador?
  • Formas erradas de se implementar o cache de navegador
  • Forma correta de se implementar o cache de navegador
  • Habilitando mod_expires e mod_headers no Apache
  • Testando a Configuração
  • Conclusão

O que é cache de navegador?

Antes de falarmos sobre as configurações do apache, devemos entender bem o que é e como funciona o cache de arquivos pelo navegador. Pois bem, sempre que um usuário acessa o seu site, todo o conteúdo disponível na página acessada pelo usuário, tais como imagens, arquivos css, arquivos javascript, arquivos xml e etc é baixado para o seu computador, permanecendo em uma pasta no seu disco rígido. Assim, quando o usuário entrar no seu site novamente, ele poderá ou não baixar todo o conteúdo novamente, vai depender das configurações de cache do navegador dele, e do seu servidor http.

Então cache é o ato de salvar os dados em um local para rápido acesso, não precisando ir buscá-lo na fonte original (servidor http). Assim sendo, a partir do primeiro acesso podemos instruir o navegador a guardar estes arquivos no disco rígido do usuário, e também podemos definir o tempo que este arquivo ficará armazenado. Assim, quando o usuário acessar o seu site novamente ou navegar por outras páginas, ao invés de precisar baixar toda a página novamente, o navegador será instruído a buscar os conteúdos diretamente do Cache. Caso ele não tenha algo no Cache ou o tempo de permanência tenha expirado, é solicitado o arquivo em questão ao servidor do site.

Note que é imensamente mais rápido buscar conteúdo do cache, do que em servidores http, que geralmente se encontram em outros países e podem inclusive estar ocupados.

Formas erradas de se implementar o cache de navegador

Uma forma bem comum de tentar fazer isso, porém extremamente inconsistente, é usar as Meta Tags Expires, Pragma e Cache-control no cabeçalho do documento, na tentativa de determinar a data e a hora em que a página expira e que os dados desta devem ser armazenados.

 <!doctype html>  
 <html dir="ltr" lang="pt-BR">  
 <head>  
 <title>Lorindo.com</title>  
 <meta http-equiv="expires" content="Tue, 05 Jan 2013 12:12:12 GMT">  
 <meta http-equiv="cache-control" content="public" /> <!-- reconhecida pelo HTTP 1.1 -->  
 <meta http-equiv="Pragma" content="public"> <!-- reconhecida por todas as versões do HTTP -->  

Ou então gerar cabeçalhos HTTP apartir de linguagens server-side, como o PHP ou Java.

 <?php  
 header("Cache-Control: private, max-age=10800, pre-check=10800");  
 header("Pragma: private");  
 header("Expires: " . date(DATE_RFC822,strtotime("30 day")));  
 ?>  

Esses métodos podem até ser muito simples de serem implementados, talvez por isso sejam tão usados, porém já estão obsoletos. Até mesmo, porque é muito mais simples configurar apenas um arquivo no servidor, do que configurar cada página separada.

Forma correta de se implementar o cache de navegador

A forma correta de se implementar e configurar o cache do navegador, é adicionando configurações no arquivo httpd.conf do apache, desta forma é possível especificar uma data de expiração para arquivos de imagem, javascript, css, mídias, pdf, flash e demais arquivos servidos pelo site.

Fazendo uma simples configuração, você consegue diminuir muito o tempo de carregamento da sua página web, garantindo uma melhor performance e experiência para os seus usuários.

Existem duas formas de se realizar Cache de navegador pelo servidor http:

  1. Cabeçalho Expires: Com o cabeçalho expires é possível determinar a expiração de um arquivo, colocando-o assim em Cache. Ele deve ser utilizado para navegadores que utilizam o protocolo HTTP 1.0 para a comunicação com o servidor.
  2. Cabeçalho Cache-Control: Com o cabeçalho Cache-Control é possível determinar a expiração de um arquivo, colocando-o assim em Cache. Além disso é possível determinar vários parâmetros adicionais, como tornar o Cache público ou privado. Ele deve ser utilizado para navegadores que utilizam o protocolo HTTP 1.1 para a comunicação com o servidor.

Após essa explicação das duas formas de controlar o cache, a dúvida geralmente é sobre qual modo deve ser usado. Pois saibam que o correto é usar os dois, definidos com os mesmos tempos de expiração, pois o navegador que trabalhar com o protocolo HTTP 1.0 utilizará o Expires, já os navegadores modernos que trabalharem com o HTTP 1.1, utilizarão o Cache-Control.

Habilitando mod_expires e mod_headers no Apache

A primeira coisa a ser feita para que o mod_expires e o mod_headers possam ser configurados, é habilitá-los no arquivo httpd.conf, conforme figura 1 abaixo.

apache-windows-hablitando-mod-headers-mod-expires-httpd.conf
Figura 1 – Habilitando o mod_expires e mod_headers no arquivo httpd.conf

Após habilitar o mod_expires e o mod_headers, podemos começar enfim a configurá-los para que nossos clientes armazenem em cache o conteúdo estático do nosso site.

Configurando o mod_expires no Apache

O mod_expires possui três diretivas principais, e são elas:

  • ExpiresActive: Setando o valor desta diretiva para “on”, permitimos que o apache faça o controle de cache nos cabeçalhos http.
  • ExpiresDefault: Esta diferiva configura o tempo padrão de expiração para todos os tipos de arquivos, no exemplo abaixo está configurado para 1 dia.
  • ExpiresByType: Esta diretiva permite definir o tipo de arquivo que receberá determinado tempo de expiração. O tempo de expiração pode ser informado em segundos, minutos, horas, dias, semanas, meses e anos, sempre respeitando as regras de sintaxe corretas.

Segue abaixo um exemplo de configuração para os principais tipos de arquivos servidos em um site.

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault "access plus 1 day"
    ExpiresByType text/cache-manifest "access plus 0 seconds"
    # Html
    ExpiresByType text/html "access plus 0 seconds"
    # Dados
    ExpiresByType text/xml "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
    # Feed
    ExpiresByType application/rss+xml "access plus 1 hour"
    ExpiresByType application/atom+xml "access plus 1 hour"
    # Favicon
    ExpiresByType image/x-icon "access plus 1 week"
    # Midia: images, video, audio
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/jpg "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType video/ogg "access plus 1 month"
    ExpiresByType audio/ogg "access plus 1 month"
    ExpiresByType video/mp4 "access plus 1 month"
    ExpiresByType video/webm "access plus 1 month"
    # Arquivos htc
    ExpiresByType text/x-component "access plus 1 month"
    # fonts
    ExpiresByType application/x-font-ttf "access plus 1 month"
    ExpiresByType font/opentype "access plus 1 month"
    ExpiresByType application/x-font-woff "access plus 1 month"
    ExpiresByType image/svg+xml "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    # css / javascript
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType application/x-javascript  "access plus 1 year"

    # Desativar cache para o arquivo index.php
    <FilesMatch "index\.php$">
        ExpiresActive Off
    </FilesMatch>

</IfModule>

Configurando o mod_headers no Apache

o mod_headers permite entre outras coisas a configurar o cache-control. A função do Cache-Control (mod_headers) é exatamente a mesma do Expires, determinar o tempo de expiração para qualquer tipo de arquivo porém definindo o tempo em segundos, e ainda determinar o tipo do cache, se ele será público, privado e etc. Apenas navegadores modernos reconhecem o cabeçalho Cache-Control.

O Cache-Control pode receber até 7 informações (separadas por vírgula):

  • max-age: A informação mais importante. Com ela definimos em segundos o tempo de expiração.
  • tipo de cache: “public” ou “private”. A diferença entre eles é a seguinte: vamos imaginar que o seu ISP tenha um proxy invisível entre você e a Internet, que esteja fazendo cache de páginas web para reduzir o tráfego necessário e consequentemente os custos operacionais. Usando “cache-control: private”, você está especificando que o ISP não deveria realizar o cache da página, mas permitindo que o cliente o faça. Se você setar o “cache-control: public”, você está informando que qualquer um poderá fazer o cache da página servida, inclusive seu ISP.
  • no-cache: Apesar desta diretiva parecer que está instruindo o navegador que não faça cache da página, há uma diferença sutil. A diretiva “no-cache”, de acordo com o RFC, diz ao navegador que ele deveria revalidar com o servidor antes de servir a página a partir do cache. Revalidar é a técnica que deixa a aplicação conserver tráfego de rede. Se a página que o navegador tem em cache não mudou, o servidor apenas sinaliza que o navegador pode servir a página do cache. Assim na teoria pelo menos, o navegador deveria armazenar a página em cache, mas exibí-la a partir do cache somente com revalidação do servidor. Porém alguns navegadores ignoram essa indicação e implementaram para esta diretiva, o mesmo comportamento da diretiva “no-store” explicada abaixo.
  • no-store: Esta é a diretiva “cache-control” mais segura. Ela diz ao navegador para não realiar o cache da página. Sempre que estiver servindo uma página com informações confidenciais, esta diretiva deverá ser usada. Perceba que a diretiva “cache-control: no-cache” também tenha passado a se comportar dessa forma, é mais seguro usar ambas as diretivas, “no-cache” e “no-store”.
  • must-revalidate: Esta diretiva insiste que o navegador deve revalidar a página contra o servidor antes de serví-la a partir do cache. Note que implicitamente ela deixa o navegador realizar o cache da página. A diretiva “no-store” é uma opção mais segura se você quiser servir uma página com informações sensíeis sem que ela fique salva em cache.
  • proxy-revalidate: Esta diretiva é similar à “must-revalidate”, exceto que ela objetiva servidores proxy. Ela diz que servidores proxy devem revalidar com o servidor quando servindo esta requisição, enquanto o navegador do usuário não necessita revalidar. Esta diretiva é útil quando cache de uma página autenticada está sendo feito pelo navegador. Você não quer que o servidor proxy tenha uma cópia em cache das suas informações confidenciais.

Abaixo segue alguns exemplos de como configurar o mod_headers

<IfModule mod_headers.c>
    # Cache-Control de 4 horas (14400 segundos) de tipo público
    <FilesMatch "\.(jpg|jpeg|png|gif|ico|css|js)$">
        Header set Cache-Control "max-age=14400, public"
    </FilesMatch>

    # Desativar cache para o arquivo index.php
    # O cabeçalho "pragma" é para compatibilidade com o IE
    <FilesMatch "index\.php$">
        Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
        Header set Pragma "no-cache"
    </FilesMatch>
</IfModule>

Por fim ainda temos as Entity tags (ETags) que são um tipo de mecanismo feito para checar se existe uma nova versão do arquivo em cache. Com esse mecanismo desabilitado, nós impedimos que o cache ou o browser fiquem tentando fazer a validação. Para desabilitar o ETag, apenas acrescente no mod_headers o seguinte: Header unset ETag, FileETag None e Header unset Last-Modified.

O mod_headers ficará conforme abaixo:

<IfModule mod_headers.c>
    # Cache-Control de 4 horas (14400 segundos) de tipo público
    <FilesMatch "\.(jpg|jpeg|png|gif|ico|css|js)$">
        Header set Cache-Control "max-age=14400, public"
    </FilesMatch>

    # Desativar cache para o arquivo index.php
    # O cabeçalho "pragma" é para compatibilidade com o IE
    <FilesMatch "index\.php$">
        Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
        Header set Pragma "no-cache"
    </FilesMatch>
    Header unset Etag
    FileETag None
    Header unset Last-Modified
</IfModule>

Lembrando que todas essas configurações devem ficar no arquivo httpd.conf ou dentro de algum bloco virtualhost.

Testando a configuração

Para testar a configuração, e comparar os cabeçalhos enviados pelo servidor, disponibilizo aqui, o conteúdo do meu arquivo hosts, e aqui o coteúdo do meu arquivo httpd-vhosts.conf. Com essa configuração vai ficar bem simples de podermos testar as nossas configurações.

A configuração disponibilizada serve no caso de algum de vocês desejarem realizar os testes e verificarem os resultados. Pois bem, vamos aos passos necessários para testar:

  • Passo 1: Colocar a configuração do servidor de acordo com a já disponibilizada.
  • Passo 2: Iniciar o serviço do Apache.
  • Passo 3: Acessar o domínio: http://www.exemplo.com. Em seguida abrir o painel de ferramentas do desenvolvedor no chrome ou firefox (F12). Abrir a aba “Network”, clicar no item que aparecer na listagem, conforme figura 3 abaixo. Observar o conteúdo do response header.
  • Passo 4: Acessar o domínio: http://www.outroexemplo.com. Em seguida abrir o painel de ferramentas do desenvolvedor no chrome ou firefox (F12). Abrir a aba “Network”, clicar no item que aparecer na listagem, conforme figura 4 abaixo. Observar o conteúdo do response header.

apache-windows-habilitando-cache-navegador-resultado-com-cache.png
Figura 3 – Resultado do cabeçalho de resposta com o cache habilitado

apache-windows-habilitando-cache-navegador-resultado-sem-cache.png
Figura 4 – Resultado do cabeçalho de resposta sem o cache habilitado

Conclusão

Habilitar o cache de navegador pelo servidor é muito importante, pois evita download desnecessários, diminuindo tráfego de rede e melhorando em muito a experiência do usuário ao acessar o seu site.

Deixe um comentário