[javascript] 브라우저가 캐시 된 CSS / JS 파일을 강제로 다시로드하는 방법?

일부 브라우저 (특히 Firefox 및 Opera)는 브라우저 세션 간에도 .css.js 파일 의 캐시 된 사본을 사용하는 데 매우 열심입니다 . 이 파일 중 하나를 업데이트 할 때 문제가 발생하지만 사용자 브라우저는 캐시 된 사본을 계속 사용합니다.

문제는 파일이 변경되었을 때 사용자 브라우저가 파일을 다시로드하도록하는 가장 우아한 방법은 무엇입니까?

이상적으로 솔루션은 브라우저가 페이지를 방문 할 때마다 파일을 다시로드하도록 강요하지 않습니다. 나는 자신의 해결책을 답변으로 게시 할 것이지만, 더 나은 해결책이 있다면 귀하의 투표가 결정되도록 할 것입니다.

업데이트 :

여기에서 잠시 동안 토론을 한 후 John Millikinda5id 의 제안이 유용하다는 것을 알았습니다 . 이것에 대한 용어 인 auto-versioning이 있습니다.

내 원래 솔루션과 John의 제안이 결합 된 새로운 답변을 아래에 게시했습니다.

SCdF 가 제안한 또 다른 아이디어 는 파일에 가짜 쿼리 문자열을 추가하는 것입니다. (거짓 쿼리 문자열로 타임 스탬프를 자동으로 사용하는 일부 Python 코드는 pi 에 의해 제출되었습니다 .) 그러나 브라우저가 쿼리 문자열로 파일을 캐시하는지 여부에 대한 논의가 있습니다. (브라우저는 파일을 캐시하고 나중에 방문 할 때 파일을 사용하기를 원합니다. 파일이 변경된 경우에만 파일을 다시 가져 오기를 원합니다.)

가짜 쿼리 문자열로 어떤 일이 발생하는지 명확하지 않기 때문에 그 대답을 받아들이지 않습니다.



답변

업데이트 : John Millikinda5id의 제안 사항을 통합하도록 다시 작성되었습니다 . 이 솔루션은 PHP로 작성되었지만 다른 언어에도 쉽게 적용 할 수 있습니다.

업데이트 2 : Nick Johnson의 의견 을 포함하여 원래 .htaccess정규식이와 같은 파일에 문제를 일으킬 수 있음을 알려줍니다 json-1.3.js. 해결책은 끝에 정확히 10 자리가있는 경우에만 다시 작성하는 것입니다. (10 자리 숫자는 2001 년 9 월 9 일부터 11/20/2286까지의 모든 타임 스탬프를 포함하기 때문에)

먼저 .htaccess에서 다음과 같은 다시 쓰기 규칙을 사용합니다.

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

이제 다음 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);
}

이제 CSS를 포함 할 때마다 다음과 같이 변경하십시오.

<link rel="stylesheet" href="/css/base.css" type="text/css" />

이에:

<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />

이런 식으로 링크 태그를 다시 수정할 필요가 없으며 사용자는 항상 최신 CSS를 볼 수 있습니다. 브라우저는 CSS 파일을 캐시 할 수 있지만 CSS를 변경하면 브라우저는이를 새로운 URL로 인식하므로 캐시 된 사본을 사용하지 않습니다.

이미지, 파비콘 및 JavaScript에서도 작동합니다. 기본적으로 동적으로 생성되지 않은 모든 것.


답변

간단한 클라이언트 측 기술

일반적으로 캐싱은 좋습니다. 따라서 웹 사이트를 개발할 때 스스로 문제를 해결하는지 또는 프로덕션 환경에서 캐시를 제어하려고하는지에 따라 몇 가지 기술이 있습니다.

웹 사이트를 방문하는 일반 방문자에게는 사이트를 개발할 때와 같은 경험이 없습니다. 평균 방문자는 사이트를 자주 방문하지 않기 때문에 (Google 또는 hi5 네트워크가 아닌 경우 한 달에 몇 번만 가능) 파일을 캐시에 보관할 가능성이 적으므로 충분할 수 있습니다. 브라우저에 새 버전을 강제 적용하려면 요청에 항상 쿼리 문자열을 추가하고 주요 변경을 수행 할 때 버전 번호를 늘릴 수 있습니다.

<script src="/myJavascript.js?version=4"></script>

이렇게하면 모든 사람이 새 파일을 얻을 수 있습니다. 브라우저가 파일의 URL을보고 캐시에 사본이 있는지 여부를 판별하기 때문에 작동합니다. 서버가 쿼리 문자열을 사용하여 설정되지 않은 경우 무시되지만 이름은 브라우저에 새 파일처럼 보입니다.

반면에 웹 사이트를 개발하는 경우 개발 버전에 변경 사항을 저장할 때마다 버전 번호를 변경하지 않으려 고합니다. 지루할 것입니다.

따라서 사이트를 개발하는 동안 쿼리 문자열 매개 변수를 자동으로 생성하는 것이 좋습니다.

<!-- Development version: -->
<script>document.write('<script src="/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"\><\/script>');</script>

요청에 쿼리 문자열을 추가하는 것이 리소스를 버전 관리하는 좋은 방법이지만 간단한 웹 사이트에서는 필요하지 않을 수 있습니다. 캐싱은 좋은 것임을 기억하십시오.

브라우저가 파일을 캐시에 보관하는 데 반드시 신경을 쓸 필요는 없다는 점도 주목할 가치가 있습니다. 브라우저에는 이런 종류의 정책이 있으며 일반적으로 HTTP 사양에 명시된 규칙에 따라 재생됩니다. 브라우저가 서버에 요청하면 응답의 일부는 EXPIRES 헤더입니다. 브라우저에 캐시에 보관해야하는 기간을 알려주는 날짜입니다. 다음에 브라우저가 동일한 파일에 대한 요청을 처리 할 때, 캐시에 사본이 있고 EXPIRES 날짜를 찾아서 사용해야하는지 여부를 결정합니다.

믿거 나 말거나, 실제로 브라우저 캐시를 영구적으로 만드는 서버입니다. 서버 설정을 조정하고 EXPIRES 헤더를 변경할 수 있지만 위에서 작성한 작은 기술은 아마도 훨씬 간단한 방법 일 것입니다. 캐싱이 양호하기 때문에 일반적으로 해당 날짜를 미래까지 ( “Fu-future Expires Header”) 설정하고 위에서 설명한 기술을 사용하여 변경을 수행하려고합니다.

HTTP에 대한 자세한 정보 나 이러한 요청을 작성하는 방법에 관심이 있다면 Steve Souders의 “고성능 웹 사이트”를 참조하십시오. 주제에 대한 아주 좋은 소개입니다.


답변

아파치 용 Google의 mod_pagespeed 플러그인은 자동 버전 관리를 수행합니다. 정말 매끄 럽습니다.

웹 서버에서 나가는 도중에 HTML을 구문 분석하고 (PHP, 레일, 파이썬, 정적 HTML 등 작동) ID 코드를 포함하도록 CSS, JS, 이미지 파일에 대한 링크를 다시 씁니다. 캐시 제어 기능이 매우 긴 수정 된 URL에서 파일을 제공합니다. 파일이 변경되면 URL이 자동으로 변경되어 브라우저가 다시 가져와야합니다. 기본적으로 코드를 변경하지 않고 작동합니다. 나가는 길에 코드를 축소 할 수도 있습니다.


답변

버전을 수동으로 변경하는 대신 실제 CSS 파일의 MD5 해시를 사용하는 것이 좋습니다.

따라서 귀하의 URL은

http://mysite.com/css/[md5_hash_here]/style.css

여전히 다시 쓰기 규칙을 사용하여 해시를 제거 할 수 있지만 이점은 URL이 동일하면 파일이 변경되지 않기 때문에 캐시 정책을 “영원히 캐시”로 설정할 수 있다는 것입니다.

그런 다음 파일의 해시를 계산하고 태그를 업데이트하는 간단한 셸 스크립트를 작성할 수 있습니다 (포함 할 별도의 파일로 옮길 수 있습니다).

CSS가 변경 될 때마다 해당 스크립트를 실행하면됩니다. 브라우저는 파일이 변경 될 때만 파일을 다시로드합니다. 수정 한 후 실행 취소하면 방문자가 다시 다운로드하지 못하도록하기 위해 어떤 버전으로 돌아 가야할지 고민 할 필요가 없습니다.


답변

왜이 솔루션을 구현하기 위해 많은 고통을 겪고 있는지 확실하지 않습니다.

파일의 수정 된 타임 스탬프를 가져 와서 파일에 쿼리 문자열로 추가하면됩니다.

PHP에서는 다음과 같이합니다.

<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">

filemtime은 파일 수정 타임 스탬프를 반환하는 PHP 함수입니다.


답변

당신은 그냥 둘 수 ?foo=12341234이 원하는대로 당신으로 변경, 당신의 CSS / JS 가져 오기의 끝에서. SO html 소스를 살펴보십시오.

그 아이디어는? 어쨌든 요청에서 매개 변수는 삭제 / 무시되며 새 버전을 출시 할 때 해당 번호를 변경할 수 있습니다.


참고 : 이것이 캐싱에 어떻게 영향을 미치는지에 관한 몇 가지 주장이 있습니다. 나는 그것의 일반적인 요지가 매개 변수 있거나없는 GET 요청을 캐싱 할 수 있어야 하므로 위의 솔루션이 작동해야한다고 생각합니다.

그러나 웹 서버는 사양의 해당 부분과 사용자가 사용하는 브라우저를 준수할지 여부를 결정해야합니다. 어쨌든 새로운 버전을 요청할 수 있기 때문입니다.


답변

이것을 “자동 버전 관리”라고 들었습니다. 가장 일반적인 방법은 정적 파일의 mtime을 URL 어딘가에 포함시키고 다시 쓰기 핸들러 또는 URL conf를 사용하여 제거하는 것입니다.

또한보십시오: