웹 브라우저가 이미지를 캐시하지 않도록 강제하는 방법
배경
두 보보 웹 사이트를 위해 매우 간단한 CGI 기반 (Perl) 컨텐츠 관리 도구를 작성하고 사용하고 있습니다. 웹 사이트 관리자에게 필드 (날짜, 장소, 제목, 설명, 링크 등)를 채우고 저장하는 이벤트에 대한 HTML 양식을 제공합니다. 이 양식에서 관리자는 이벤트와 관련된 이미지를 업로드 할 수 있습니다. 양식을 표시하는 HTML 페이지에서 업로드 된 사진의 미리보기 (HTML img 태그)도 표시됩니다.
문제
관리자가 사진을 변경하려고 할 때 문제가 발생합니다. 그는 "찾아보기"버튼을 눌러 새 사진을 선택합니다. 그리고 작동합니다.
이미지가 업로드되면 백엔드 CGI가 업로드를 처리하고 양식을 다시로드합니다.
문제는 이미지 가 새로 고쳐 지지는 것 입니다. 데이터베이스가 올바른 이미지를 보유해도 이전 이미지는 여전히 표시됩니다. 웹 브라우저에서 이미지가 캐시되고 사실로 좁혔습니다. 관리자가 Firefox / Explorer / Safari에서 RELOAD 버튼을 클릭하면 모든 것이 제대로 새로 고쳐지고 새 이미지가 나타납니다.
내 솔루션 작동하지 않음
과거의 날짜와 함께 HTTP Expires를 작성하여 캐시를 제어합니다.
Expires: Mon, 15 Sep 2003 1:00:00 GMT
나는 관리 할 수있는 페이지가 항상 종료되어 페이지를로드하는 데 시간이 조금 더 많이 신경 쓰지 언어입니다.
그러나 작동하지 않습니다.
노트
파일 이름이 데이터베이스에 유지되지 않습니다. Image.jpg 로 이름이 바뀌 었었 습니다 (사용할 때 간단히 표시). 기존 이미지를 새 이미지로 바꾸면 이름도 바뀌지 않습니다. 이미지 파일의 내용 만 변경됩니다.
웹 서버는 호스팅 서비스 / ISP에서 제공합니다. Apache를 사용합니다.
질문
웹 브라우저가 이미지가 아닌이 페이지의 내용을 캐시하지 않도록 할 수있는 방법이 있습니까?
실제로 데이터베이스에 "파일 이름 저장"옵션을 사용하고 있습니다. 이렇게하면 이미지가 변경되면 IMG 태그의 src도 변경됩니다. 더 나은 솔루션이 필요하지 않습니다. 또한 사진 업로드 된 새 이미지의 이름이 같은 경우에도 여전히 작동하지 (예 : 이미지가 약간의 샵으로 재 업로드 됨).
Armin Ronacher는 올바른 아이디어를 가지고 있습니다. 문제는 임의의 것입니다. 나는 사용할 것이다 :
<img src="picture.jpg?1222259157.415" alt="">
여기서 "1222259157.415"는 서버의 현재 시간입니다.
Javascript performance.now()
또는 Python으로 시간 생성time.time()
간단한 수정 : 임의의 쿼리를 상위에 첨부하십시오.
<img src="foo.cgi?random=323527528432525.24234" alt="">
HTTP RFC의 내용 :
Cache-Control: no-cache
그러나 그것은 잘 작동하지 않습니다.
내가 사용하는 PHP의 파일 수정 시간 기능을 예를 들어 :
echo <img src='Images/image.png?" . filemtime('Images/image.png') . "' />";
이미지를 변경하면 수정 된 타임 스탬프가 다르기 때문에 캐시 된 이미지 대신 새 이미지가 사용됩니다.
나는 사용할 것이다 :
<img src="picture.jpg?20130910043254">
여기서 "20130910043254"는 파일의 수정 시간입니다.
파일 이름이 데이터베이스에 유지되지 않습니다. Image.jpg로 이름이 바뀌 었습니다 (사용할 때 간단히 표시). 기존 이미지를 새 이미지로 바꾸면 이름도 바뀌지 않습니다. 이미지 파일의 내용 만 변경됩니다.
1) 가장 먼저 생각하는 것 (생성하기 쉬운 솔루션), 2) 생각하기 후에 끝내는 것 (쉽기 때문에) 사용하다). 분명히, 당신은 항상 이익을 얻지 못할 것입니다. 그러나 두 번째 옵션은 다소 과소 평가되었습니다. 왜 php
그렇게 인기가 있는지 생각해보세요 .)
이미지를 제공하기위한 프록시 펼쳐져 있습니다. 서류가 작성을 좋아합니다 :
HTML :
<img src="image.php?img=imageFile.jpg&some-random-number-262376" />
펼쳐보기 :
// PHP
if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {
// read contents
$f = open( IMG_PATH . $_GET['img'] );
$img = $f.read();
$f.close();
// no-cache headers - complete set
// these copied from [php.net/header][1], tested myself - works
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
// image related headers
header('Accept-Ranges: bytes');
header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
header('Content-Type: image/jpeg'); // or image/png etc
// actual image
echo $img;
exit();
}
실제로 이미지 src의 캐시 없음 헤더 또는 난수는 충분하지만 방탄을 원하기 때문에 ..
나는 새로운 코더이지만 브라우저가 캐싱하고있는 뷰를 유지하지 않습니다하기 위해 다음과 같이했습니다.
<meta Http-Equiv="Cache" content="no-cache">
<meta Http-Equiv="Pragma-Control" content="no-cache">
<meta Http-Equiv="Cache-directive" Content="no-cache">
<meta Http-Equiv="Pragma-directive" Content="no-cache">
<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">
어떤 브라우저에서 작동하는지 확실하지 않지만 일부에서는 작동합니다. IE : 웹 페이지를 새로 고칠 때와 웹 사이트를 다시 방문 할 때 (새로 고침없이) 작동합니다. CHROME : 웹 페이지를 새로 고침 할 때만 작동합니다 (다시 방문한 후에도). SAFARI 및 iPad : 작동하지 않습니다. 기록 및 웹 데이터를 삭제해야합니다.
SAFARI / iPad에 대한 아이디어가 있습니까?
사용 클래스 = "NO-CACHE"없다
샘플 html :
<div>
<img class="NO-CACHE" src="images/img1.jpg" />
<img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>
jQuery :
$(document).ready(function ()
{
$('.NO-CACHE').attr('src',function () { return $(this).attr('src') + "?a=" + Math.random() });
});
자바 스크립트 :
var nods = document.getElementsByClassName('NO-CACHE');
for (var i = 0; i < nods.length; i++)
{
nods[i].attributes['src'].value += "?a=" + Math.random();
}
결과 : src = "images / img1.jpg" => src = "images / img1.jpg? a = 0.08749723793963926"
이미지를 업로드 할 때 파일 이름은 데이터베이스에 보관되지 않습니다. Image.jpg로 이름이 변경되었습니다 (사용할 때 간단히 표시).
이것을 변경하면 문제가 해결되었습니다. 위에서 제안한 솔루션과 마찬가지로 타임 스탬프를 사용합니다. Image- <timestamp> .jpg
아마도 이미지에 대해 동일한 파일 이름을 유지함으로써 피하는 문제는 무엇이든 극복 할 수 있지만 그 문제가 무엇인지는 말할 수 없습니다.
나는 웹에서 모든 답변을 확인했고 최고의 답변은 다음과 같았습니다. (실제로는 그렇지 않습니다)
<img src="image.png?cache=none">
처음에.
그러나 cache = none 매개 변수 (정적 "none"단어)를 추가하면 아무 영향도주지 않고 브라우저는 여전히 캐시에서로드됩니다.
이 문제에 대한 해결책은 다음과 같습니다.
<img src="image.png?nocache=<?php echo time(); ?>">
기본적으로 유닉스 타임 스탬프를 추가하여 매개 변수를 동적으로 만들고 캐시를 사용하지 않는 경우 작동했습니다.
그러나 내 문제는 약간 달랐습니다. 즉석에서 생성 된 PHP 차트 이미지를로드하고 $ _GET 매개 변수로 페이지를 제어했습니다. URL GET 매개 변수가 동일하게 유지 될 때 캐시에서 이미지를 읽고 GET 매개 변수가 변경 될 때 캐시하지 않기를 원했습니다.
이 문제를 해결하기 위해 $ _GET을 해시해야했지만 여기에 배열이기 때문에 해결책이 있습니다.
$chart_hash = md5(implode('-', $_GET));
echo "<img src='/images/mychart.png?hash=$chart_hash'>";
편집 :
위의 솔루션은 잘 작동하지만 파일이 변경 될 때까지 캐시 된 버전을 제공하고 싶을 때가 있습니다. (위의 솔루션을 사용하면 해당 이미지에 대한 캐시가 완전히 비활성화됩니다.) 따라서 브라우저에서 캐시 된 이미지를 제공하려면 이미지 파일 사용이 변경 될 때까지 다음과 같이하십시오.
echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";
filemtime ()은 파일 수정 시간을 가져옵니다.
문제는 Expires:
헤더 에도 불구하고 브라우저가 캐시를 확인하는 대신 업데이트되기 전의 이미지의 메모리 내 사본을 재사용하고 있다는 것입니다.
나는 상점과 같은 사이트의 관리 백엔드에서 제품 이미지를 업로드하는 것과 매우 유사한 상황을 겪었고, 내 경우에는 다른 사람들의 URL 수정 기술을 사용하지 않고 자바 스크립트를 사용하여 이미지를 강제로 새로 고치는 것이 최선의 선택이라고 결정했습니다. 여기에서 이미 언급했습니다. 대신 location.reload(true)
IFRAME의 창에서 호출되는 숨겨진 IFRAME에 이미지 URL을 넣은 다음 페이지에서 내 이미지를 대체했습니다. 이렇게하면 내가있는 페이지뿐만 아니라 나중에 방문하는 페이지에서도 이미지가 새로 고침됩니다. 클라이언트 나 서버가 URL 쿼리 문자열이나 조각 식별자 매개 변수를 기억할 필요가 없습니다.
여기 에 내 대답에 몇 가지 코드를 게시했습니다 .
타임 스탬프 추가 <img src="picture.jpg?t=<?php echo time();?>">
항상 파일 끝에 임의의 숫자를 부여하고 캐싱을 중지합니다.
사용자와 클라이언트 사이에 제대로 작동하지 않는 투명 프록시의 가능성이 있으므로 이미지가 캐시되지 않도록 완전히 보장하는 유일한 방법은 쿼리 문자열이나 클라이언트의 일부로 타임 스탬프를 태그하는 것과 같은 고유 한 URI를 제공하는 것입니다. 통로.
해당 타임 스탬프가 이미지의 마지막 업데이트 시간에 해당하는 경우 필요할 때 캐시하고 적시에 새 이미지를 제공 할 수 있습니다.
원래 질문은 텍스트 정보와 함께 저장된 이미지에 관한 것이라고 가정합니다. 따라서 src = ... url을 생성 할 때 텍스트 컨텍스트에 액세스 할 수 있다면 무의미한 랜덤 또는 타임 스탬프 대신 이미지 바이트의 CRC32 저장 / 사용을 고려하십시오. 그러면 이미지가 많은 페이지가 표시되면 업데이트 된 이미지 만 다시로드됩니다. 결국 CRC 저장이 불가능한 경우 런타임에 계산하여 URL에 추가 할 수 있습니다.
내 관점에서 이미지 캐싱을 비활성화하는 것은 나쁜 생각입니다. 조금도.
여기서 근본적인 문제는 서버 측에서 업데이트되었을 때 브라우저가 이미지를 업데이트하도록 강제하는 방법입니다.
다시 말하지만, 개인적 관점에서 가장 좋은 해결책은 이미지에 대한 직접 액세스를 비활성화하는 것입니다. 대신 서버 측 필터 / 서블릿 / 기타 유사한 도구 / 서비스를 통해 이미지에 액세스합니다.
제 경우에는 이미지를 반환하고 응답으로 ETag를 첨부하는 나머지 서비스입니다. 서비스는 모든 파일의 해시를 유지하며, 파일이 변경되면 해시가 업데이트됩니다. 모든 최신 브라우저에서 완벽하게 작동합니다. 예, 구현하는 데 시간이 걸리지 만 그만한 가치가 있습니다.
유일한 예외는 파비콘입니다. 어떤 이유로 작동하지 않습니다. 브라우저가 서버 측에서 캐시를 업데이트하도록 강제 할 수 없습니다. ETags, Cache Control, Expires, Pragma 헤더, 아무것도 도움이되지 않았습니다.
이 경우 임의 / 버전 매개 변수를 URL에 추가하는 것이 유일한 해결책 인 것 같습니다.
이상적으로는 콘텐츠 동기화 옵션을 사용하여 각 웹 페이지에 버튼 / 키 바인딩 / 메뉴를 추가해야합니다.
이렇게하려면 동기화해야 할 수있는 리소스를 추적하고 xhr을 사용하여 동적 쿼리 문자열로 이미지를 조사하거나 동적 쿼리 문자열을 사용하여 src로 런타임에 이미지를 만듭니다. 그런 다음 브로드 캐스팅 메커니즘을 사용하여 리소스를 사용하는 웹 페이지의 모든 구성 요소를 업데이트하여 URL에 동적 쿼리 문자열이 추가 된 리소스를 사용하도록 알립니다.
순진한 예는 다음과 같습니다.
일반적으로 이미지가 표시되고 캐시되지만 사용자가 버튼을 누르면 xhr 요청이 리소스에 추가되고 시간 쿼리 문자열이 추가됩니다. 각 프레스마다 시간이 다를 수 있다고 가정 할 수 있기 때문에 리소스가 쿼리를 기반으로 서버 측에서 동적으로 생성되는지 아니면 정적인지 여부를 알 수 없기 때문에 브라우저가 캐시를 우회하는지 확인합니다. 쿼리를 무시하는 리소스입니다.
결과적으로 모든 사용자가 항상 리소스 요청으로 폭격하는 것을 피할 수 있지만 동시에 사용자가 동기화되지 않은 것으로 의심되는 경우 리소스를 업데이트 할 수있는 메커니즘을 허용합니다.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="mobile-web-app-capable" content="yes" />
<title>Resource Synchronization Test</title>
<script>
function sync() {
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var images = document.getElementsByClassName("depends-on-resource");
for (var i = 0; i < images.length; ++i) {
var image = images[i];
if (image.getAttribute('data-resource-name') == 'resource.bmp') {
image.src = 'resource.bmp?i=' + new Date().getTime();
}
}
}
}
xhr.open('GET', 'resource.bmp', true);
xhr.send();
}
</script>
</head>
<body>
<img class="depends-on-resource" data-resource-name="resource.bmp" src="resource.bmp"></img>
<button onclick="sync()">sync</button>
</body>
</html>
참고 URL : https://stackoverflow.com/questions/126772/how-to-force-a-web-browser-not-to-cache-images
'IT' 카테고리의 다른 글
JavaScript 배열 (JSON 형식)을 동적으로 작성하는 방법 (0) | 2020.07.23 |
---|---|
round ()가 반올림되지 않는 것 (0) | 2020.07.23 |
Heroku bash 쉘에서 어떤 텍스트 편집기를 사용할 수 있습니까? (0) | 2020.07.23 |
링크를 클릭하여 JavaScript로 양식을 출시하는 방법은 무엇입니까? (0) | 2020.07.23 |
Android : DB 버전 업그레이드 및 새 테이블 추가 (0) | 2020.07.23 |