Notei que alguns navegadores (em particular, Firefox e Opera) são muito zelosos no uso de cópias em cache dos arquivos .css e .js, mesmo entre sessões de navegação. Isso leva a um problema quando você atualiza um desses arquivos, mas o navegador do usuário's continua usando a cópia em cache.
A questão é: qual é a maneira mais elegante de forçar o usuário's browser a recarregar o arquivo quando ele tiver mudado?
O ideal seria que a solução não obrigasse o navegador a recarregar o arquivo em cada visita à página. Eu publicarei a minha própria solução como resposta, mas estou curioso se alguém tem uma solução melhor e eu'deixarei os seus votos decidir.
Actualização :
Depois de permitir a discussão aqui por um tempo, encontrei a sugestão de John Millikin* e *da5id's para ser útil. Acontece que existe um termo para isto: **auto-versão***.
Eu postei uma nova resposta abaixo que é uma combinação da minha solução original com a sugestão de John's.
Outra idéia que foi sugerida por SCdF seria anexar uma falsa query string ao arquivo. (Algum código Python para usar automaticamente o timestamp como uma string de consulta falsa foi submetido por pi). No entanto, há alguma discussão sobre se o navegador irá ou não fazer o cache de um arquivo com uma query string. (Lembre-se, nós queremos que o navegador faça o cache do arquivo e o utilize em visitas futuras. Nós só queremos que ele vá buscar o arquivo novamente quando ele tiver sido alterado).
Como não está claro o que acontece com uma falsa seqüência de perguntas, eu não estou aceitando essa resposta.
Actualizado: Reescrito para incorporar sugestões de John Millikin e da5id. Esta solução é escrita em PHP, mas deve ser facilmente adaptada a outras linguagens.
Atualização 2: Incorporando comentários de **Nick Johnson*** que o regex original .htaccess
pode causar problemas com arquivos como json-1.3.js
. A solução é reescrever somente se houver exatamente 10 dígitos no final. (Porque 10 dígitos cobrem todos os timestamps de 9/9/2001 a 20/11/2286).
Primeiro, nós usamos a seguinte regra de reescrita em .htaccess:
RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]
Agora, nós escrevemos a seguinte função PHP:
/**
* Given a file, i.e. /css/base.css, replaces it with a string containing the
* file's mtime, i.e. /css/base.1221534296.css.
*
* @param $file The file to be loaded. Must be an absolute path (i.e.
* starting with slash).
*/
function auto_version($file)
{
if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
return $file;
$mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}
Agora, onde quer que inclua o seu CSS, mude-o a partir disto:
<link rel="stylesheet" href="/css/base.css" type="text/css" />
A isto:
<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />
Desta forma, você nunca mais terá que modificar a tag do link, e o usuário sempre verá o último CSS. O navegador será capaz de fazer o cache do arquivo CSS, mas quando você fizer qualquer alteração no seu CSS, o navegador verá isso como um novo URL, então ele não usará a cópia em cache.
Isto também pode funcionar com imagens, favicons, e JavaScript. Basicamente, qualquer coisa que não seja gerada dinamicamente.
Você pode simplesmente colocar ?foo=1234
no final da sua importação de css / js, mudando 1234 para ser o que você quiser. Dê uma olhada na fonte SO html para um exemplo.
A ideia é que os parâmetros ? são descartados / ignorados no pedido de qualquer maneira e você pode mudar esse número quando você lançar uma nova versão.
Nota: Há algum argumento em relação a como isto afecta exactamente o caching. Eu acredito que a essência geral é que os pedidos de GET, com ou sem parâmetros deveriam ser caches, então a solução acima deve funcionar.
No entanto, cabe tanto ao servidor web decidir se quer aderir a essa parte das especificações quanto ao navegador que o usuário usa, pois ele pode simplesmente ir em frente e pedir uma nova versão de qualquer forma.
Já ouvi isto chamado "auto versioning". O método mais comum é incluir o mtime do arquivo estático em algum lugar na URL, e retirá-lo usando manipuladores de reescrita ou confs da URL:
Veja também: