매개 변수를 통한 캐시 무효화


123

우리는 프로덕션 배포시 버스트를 캐시하고 싶지만 그렇게하기위한 시스템을 찾는 데 많은 시간을 낭비하지 않습니다. 내 생각은 현재 버전 번호로 css 및 js 파일 끝에 매개 변수를 적용하는 것이 었습니다.

<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>

두 가지 질문 : 이것이 캐시를 효과적으로 손상시킬까요? 매개 변수가 동적 콘텐츠임을 나타 내기 때문에 매개 변수는 브라우저가 해당 URL의 응답을 캐시하지 않도록할까요?

답변:


115

매개 변수 ?v=1.123는 쿼리 문자열을 나타내므로 브라우저는이 경로를 ?v=1.0. 따라서 캐시가 아닌 파일에서로드됩니다. 원하는대로.

그리고, 브라우저는 소스 당신이 전화 같은 다음에 남아있을 것입니다 가정합니다 ?v=1.123합니다 해당 문자열로 캐시를. 따라서 이동하기 전까지는 서버가 설정되어 있더라도 캐시 된 상태로 유지 ?v=1.124됩니다.


4
Steve Souders 인용 : "인기있는 프록시에 의한 캐싱의 이점을 얻으려면 쿼리 문자열을 사용하지 말고 파일 이름 자체를 변경하십시오." 전체 설명은 여기에서 찾을 수 있습니다 : stevesouders.com/blog/2008/08/23/…
lao

25
그 블로그 게시물은 이제 10 년이 다되어 가고 있습니다. 캐시 공급자와 CDN이 아직이를 수용하지 못했다고 생각하십니까? Squid는 이제 쿼리 문자열로 문서를 캐시 할 수있는 것 같습니다 .
jeteon

1
이것은 누군가에게 도움이 될 수 있습니다. 개인적으로 저는 파일 수정 타임 스탬프를 '자동'버전 매개 변수로 사용합니다. <link rel="stylesheet" href="style.css?v=1487935578" />
oelna

나는 개인적으로 그 이유를 이해하지 못하지만 Lara Hogan (Swanson) (Etsy의 엔지니어링 관리자)은 캐시 무효화에 쿼리 매개 변수 사용을 권장하지 않습니다. 사용자와 서버 간의 캐시 프록시와 관련이 있다고 생각합니다.
Sam Rueby

36

두 가지 질문 : 이것이 캐시를 효과적으로 손상시킬까요?

예. 스택 오버플로조차도이 방법을 사용 하지만 , (하루에 수백만 명의 방문자와 수많은 클라이언트 및 프록시 버전 및 구성으로) 캐시를 깨기에는 충분하지 않은 이상한 경우가있었습니다. 그러나 일반적인 가정은 이것이 작동 할 것이며 클라이언트에서 캐싱을 중단하는 데 적합한 방법이라는 것입니다.

매개 변수가 동적 콘텐츠임을 나타 내기 때문에 매개 변수는 브라우저가 해당 URL의 응답을 캐시하지 않도록할까요?

아니요. 매개 변수는 캐싱 정책을 변경하지 않습니다. 서버에서 보낸 캐싱 헤더는 여전히 적용되며, 보내지 않으면 브라우저의 기본값이 적용됩니다.


1
@spender 지금은 참조를 찾을 수 없습니다. 두렵습니다. Jeff Atwood가 이에 대해 이야기하는 긴 블로그 기사 또는 SO 답변이있었습니다 (IIRC)
Pekka

2
@spender 일부 프록시 서버 (이전 또는 구성 가능)는 캐싱 할 때 쿼리 문자열을 무시한다는 것을 읽었습니다.
MrWhite

2
@spender-같은 말을 들었고 파일 이름이나 경로를 변경하는 것이 최선의 선택이라고 생각합니다. 그냥, 예를 들어, 버전 폴더 이름 아래의 모든 정적 파일을 이동할 수 있도록 쉬운 수 있습니다 /static/v22/file.css당신은 하나의 폴더 이름 변경, 예를 들어, 여러 파일을 할 수 있기 때문에, /static/v23/file.css/static/v23/mystuff.js
브래드 공원

22

실제 파일 이름에 버전 번호를 입력하는 것이 더 안전합니다. 이를 통해 한 번에 여러 버전이 존재할 수 있으므로 새 버전을 롤아웃 할 수 있으며 이전 버전을 요청하는 캐시 된 HTML 페이지가 여전히 존재하는 경우 HTML에서 작동하는 버전을 가져옵니다.

인터넷상의 가장 큰 버전 배포 중 하나에서 jQuery는 실제 파일 이름에 버전 번호를 사용하며 특별한 서버 측 논리없이 여러 버전이 안전하게 공존 할 수 있습니다 (각 버전은 다른 파일 일 뿐임).

이렇게하면 새 페이지와 새 링크 된 파일 (원하는 것)을 배포 할 때 캐시가 한 번 파열되고 이후 해당 버전이 효과적으로 캐시 될 수 있습니다 (원하는 것).


동의하지만 Sinatra가 모든 css 및 js 요청에? v = <% = VERSION %>을 추가하는 것이 모든 파일을 개별적으로 제어하는 ​​것보다 훨씬 쉽습니다. 결국 우리는 sinatra-assetpack으로 전환하여 모든 파일을 사전 처리하고 압축하고 실제로 파일 이름에 버전 #을 추가합니다. 그러면 개별적으로 훨씬 쉽게 제어 할 수 있습니다.
Brad Herman

1
10000 % 확실하게하고 싶다면 파일 이름에 버전 번호를 넣는 것이 가장 안전한 해결책이라는 데 동의하지만 "한 번에 여러 버전이 존재하는"주장을 따르지 않습니다. 검색어 매개 변수가있는 URL은 검색어 매개 변수가 다른 동일한 URL과 다릅니다. 클라이언트는 두 개의 서로 다른 리소스로 처리해야합니다. 그렇지 않은 경우 클라이언트가 손상됩니다.
Pekka 2011 년

2
@Pekka-버전 번호는 한 번에 여러 버전이 존재할 수 있지만 쿼리 매개 변수를 올바른 실제 파일에 매핑하려면 서버 협력이 필요합니다. 나는 그것이 OP가 여기에서하는 일이라고 생각하지 않으며 파일 이름을 수정할 때 복잡성이 훨씬 더 간단하고 서버 협력이 필요하지 않습니다. 분명히 둘 다 작동 할 수 있습니다.
jfriend00

11

다른 사람들이 말했듯이 쿼리 매개 변수를 사용한 캐시 무효화는 일반적으로 잘못된 아이디어 (tm)로 간주되며 오랫동안 사용되어 왔습니다. 파일 이름에 버전을 반영하는 것이 좋습니다. Html5 Boilerplate 특히 쿼리 문자열 사용을 권장하지 않습니다 .

즉, 출처를 인용 한 내가 본 권장 사항 중 모두 Steve Souders 의 2008 년 기사 에서 지혜를 얻은 것 같습니다 . 그의 결론은 당시 프록시의 행동을 기반으로했으며 요즘에는 관련성이있을 수도 있고 아닐 수도 있습니다. 그러나 최신 정보가없는 경우 파일 이름을 변경하는 것이 안전한 옵션입니다.


9

클라이언트가 리소스를 다운로드 한 후 다음과 같은 경우가 아니면 다른 모든 응답이 클라이언트 캐시에서 제공됩니다.

  1. v 매개 변수가 업데이트됩니다.
  2. 클라이언트가 캐시를 지 웁니다.

6

일반적으로 이것은 문제가 없지만 요청 매개 변수를 무시하도록 구성된 중간 캐시 (프록시)가있는 경우 작동하지 않을 수 있습니다.

예를 들어 Akamai CDN을 통해 정적 콘텐츠를 제공하는 경우이 방법을 사용하여 캐시 무효화를 방지하기 위해 요청 매개 변수를 무시하도록 구성 할 수 있습니다.


5

캐싱이 얼마나 강력하기를 원하는지에 따라 크게 달라집니다. 예를 들어 squid 프록시 서버 (및 기타)는 기본적으로 쿼리 문자열과 함께 제공된 URL을 캐싱 하지 않습니다 . 적어도 해당 기사가 작성되었을 때 그렇게했습니다. 불필요한 캐시 누락을 유발하는 특정 사용 사례를 신경 쓰지 않는다면 쿼리 매개 변수를 사용하십시오. 그러나이 문제를 방지하는 파일 이름 기반 캐시 무효화 체계를 설정하는 것은 매우 쉽습니다.


5
Steve Souders 기사에서 인용 된 squid 프록시는 기본 캐싱 정책을 변경했습니다. 버전 2.7 (2008 년 5 월) 및 버전 3.1 (2010 년 3 월) 이후 기본 동작은 동적 콘텐츠를 캐시하는 것입니다.
Josh Rack

5

여기에서 두 가지 기술 (쿼리 문자열 대 파일 이름)의 비교를 찾았 습니다 .

쿼리 문자열로서의 버전에는 두 가지 문제가 있습니다.

첫째, 우리가 파산해야하는 캐싱을 구현하는 브라우저가 항상있는 것은 아닙니다. 특정 (아마도 오래된) 프록시는 캐싱 동작과 관련하여 쿼리 문자열을 무시한다고합니다.

둘째, 여러 프런트 엔드 및 / 또는 여러 백엔드 서버가있는 좀 더 복잡한 배포 시나리오에서 업그레이드는 즉각적이지 않습니다. 자산의 이전 버전과 새 버전을 동시에 제공 할 수 있어야합니다. 예를 들어 이것이 Google App Engine을 사용할 때 어떤 영향을 미치는지 확인하십시오.


4

또 다른 유사한 접근 방식은 htaccess mod_rewrite 를 사용 하여 파일을 제공 할 때 경로의 일부를 무시하는 것입니다. 캐시되지 않은 색인 페이지는 파일의 최신 경로를 참조합니다.

개발 관점에서 보면 버전 번호에 매개 변수를 사용하는 것만 큼 쉽지만 파일 이름 접근 방식만큼 강력합니다.

버전 번호에 대해 경로의 무시 된 부분을 사용하면 서버는이를 무시하고 캐시되지 않은 파일을 제공합니다.

1.2.3/css/styles.csscss/styles.css첫 번째 디렉토리가 htaccess 파일에 의해 제거되고 무시되기 때문에 동일한 파일을 제공 합니다.

버전이 지정된 파일 포함

<?php
  $version = "1.2.3";
?>

<html>
  <head>
    <meta http-equiv="cache-control" content="max-age=0" />
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
    <meta http-equiv="pragma" content="no-cache" />
    <link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
  </head>
  <body>
    <script src="<?php echo $version ?>/js/main.js"></script>
  </body>
</html>

이 접근 방식은 색인 페이지의 캐싱을 비활성화해야 함을 의미합니다 . 모든 브라우저에서 <meta> 태그를 사용하여 캐싱을 해제 하시겠습니까?

.htaccess 파일

RewriteEngine On

# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f 
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d 

# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L] 

URL 재 작성을 허용하는 모든 서버 플랫폼에서 동일한 접근 방식을 취할 수 있습니다.

( mod_rewrite 에서 조정 된 재 작성 조건 -/ #! /를 제외한 쿼리 문자열로 디렉토리 재 작성 )

... 인덱스 페이지 / 사이트 진입 점에 대해 캐시 무효화가 필요한 경우 항상 JavaSript사용 하여 새로 고칠 수 있습니다.


2
<script type="text/javascript">
// front end cache bust

var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];   
for (i=0; i < cacheBust.length; i++){
     var el = document.createElement('script');
     el.src = cacheBust[i]+"?v=" + Math.random();
     document.getElementsByTagName('head')[0].appendChild(el);
}
</script> 

새 릴리스를 개발 / 테스트하는 동안 브라우저, 서버 및 때로는 3G 통신사 (모바일 배포를 수행하는 경우)가 정적 콘텐츠 (예 : JS, CSS, HTML, img)를 캐시하기 때문에 캐시가 문제가 될 수 있습니다. URL에 버전 번호, 임의 번호 또는 타임 스탬프를 추가하여이 문제를 해결할 수 있습니다. 예 : JSP : <script src = "js / excel.js? time = <% = new java.util.Date () %>"> </ script> 서버 페이지 JSP, ASP, PHP 대신 순수한 HTML을 실행하는 경우 서버가 도움이되지 않습니다. 브라우저에서 링크 그러므로 당신이 JS 그들을 링크를 제거하고로드 할 수는 JS 실행되기 전에로드
Conete 크리스티안

동기식으로 JS 파일을 순서대로로드 할 것이라고 생각하지 않습니다.
Stealth Rabbi

0
 <script>
    var storedSrcElements = [
         "js/exampleFile.js",
         "js/sampleFile.js",
         "css/style.css"
          ];

    var head= document.getElementsByTagName('head')[0];
    var script;
    var link;
    var versionNumberNew = 4.6;

    for(i=0;i<storedSrcElements.length;i++){
     script= document.createElement('script');
     script.type= 'text/javascript';
     script.src= storedSrcElements[i] + "?" + versionNumberNew;
     head.appendChild(script);
    }     


     </script> 


       ### Change the version number  (versionNumberNew) when you want the new files to be loaded  ###

0

이것이 외부 JS 파일을 삽입하는 데 도움이되기를 바랍니다.

<script type="text/javascript"> 
var cachebuster = Math.round(new Date().getTime() / 1000); 
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>

소스 -JavaScript의 캐시 버스터 코드

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.