문제

배경

저는 두 개의 프로 보노 웹 사이트에 매우 간단한 CGI 기반 (PERL) 컨텐츠 관리 도구를 작성하고 사용하고 있습니다. 웹 사이트 관리자에게 필드 (날짜, 장소, 제목, 설명, 링크 등)를 채우고 저장하는 이벤트에 대한 HTML 양식을 제공합니다. 이 양식에서 관리자는 이벤트와 관련된 이미지를 업로드 할 수 있습니다. 양식을 표시하는 HTML 페이지에 업로드 된 그림 (HTML IMG 태그)의 미리보기도 표시됩니다.

문제

관리자가 그림을 변경하려는 경우 문제가 발생합니다. 그는 단지 "찾아보기"버튼을 누르고 새 사진을 골라 확인해야합니다. 그리고 이것은 잘 작동합니다.

이미지가 업로드되면 백엔드 CGI가 업로드를 처리하고 양식을 올바르게 다시로드합니다.

문제는 이미지가 표시된다는 것입니다 하지 않습니다 새로 고침. 데이터베이스가 올바른 이미지를 보유하고 있지만 이전 이미지는 여전히 표시됩니다. 이미지가 웹 브라우저에 캐시되었다는 사실로 좁혔습니다. 관리자가 Firefox/Explorer/Safari에서 Reload 버튼을 누르면 모든 것이 정상적으로 새로 고쳐지고 새 이미지가 나타납니다.

내 해결책 - 작동하지 않습니다

HTTP를 작성하여 캐시를 제어하려고 노력하고 있습니다.

Expires: Mon, 15 Sep 2003 1:00:00 GMT

나는 행정 측면에 있으며 페이지가 항상 만료되어로드하는 데 시간이 조금 더 걸리는지는 신경 쓰지 않습니다.

그러나 이것은 작동하지 않습니다.

메모

이미지를 업로드 할 때 파일 이름은 데이터베이스에 보관되지 않습니다. 이름이 바뀌 었습니다 image.jpg (사용할 때 간단히 말해야합니다). 기존 이미지를 새 이미지로 교체 할 때 이름도 변경되지 않습니다. 이미지 파일의 내용 만 변경됩니다.

웹 서버는 호스팅 서비스/ISP에서 제공합니다. 아파치를 사용합니다.

의문

웹 브라우저가 이미지가 아닌이 페이지에서 물건을 캐시하지 않도록 강제하는 방법이 있습니까?

실제로 데이터베이스로 "파일 이름을 저장"하는 옵션으로 저글링하고 있습니다. 이런 식으로 이미지가 변경되면 IMG 태그의 SRC도 변경됩니다. 그러나 이것은 사이트 전체에 많은 변화가 필요하며 더 나은 솔루션이 있다면 오히려 그렇게하지 않습니다. 또한 업로드 된 새 이미지가 동일한 이름을 갖는 경우에는 여전히 작동하지 않습니다 (이미지가 약간 포토샵으로 재 설계되고 재 지원됩니다).

도움이 되었습니까?

해결책

Armin Ronacher는 올바른 아이디어를 가지고 있습니다. 문제는 임의의 문자열이 충돌 할 수 있다는 것입니다. 나는 사용할 것이다 :

<img src="picture.jpg?1222259157.415" alt="">

여기서 "122259157.415"는 서버의 현재 시간입니다.
JavaScript로 시간을 생성하십시오 performance.now() 또는 파이썬으로 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) 먼저 떠오르는 솔루션 (직접적인 솔루션, 쉽게 생각하기 쉽기 때문에) 사용). 분명히, 당신이 생각을 생각하기로 선택했다면 항상 혜택을받을 수는 없습니다. 그러나 두 번째 옵션은 오히려 과소 평가되었다고 생각합니다. 그 이유 만 생각하십시오 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에 대한 아이디어가 있습니까?

사용 class = "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 = "이미지/img1.jpg? a = 0.08749723793963926"

이미지를 업로드 할 때 파일 이름은 데이터베이스에 보관되지 않습니다. image.jpg로 이름이 바뀌 었습니다 (사용할 때 간단히 말해).

이것을 바꾸면 문제를 해결했습니다. 위에서 제안한 솔루션과 마찬가지로 타임 스탬프를 사용합니다. 영상-u003Ctimestamp> .jpg

아마도 이미지에 대한 동일한 파일 이름을 유지함으로써 피하는 문제는 극복 될 수 있지만, 그들이 무엇인지 말하지는 않습니다.

웹 주변의 모든 답변을 확인했는데 가장 좋은 답은 다음과 같습니다. (실제로는 그렇지 않습니다)

<img src="image.png?cache=none">

처음에는.

그러나 추가하면 캐시 = 없음 매개 변수 (정적 "없음"Word)는 아무것도 영향을 미치지 않으며 브라우저는 여전히 캐시에서로드됩니다.

이 문제에 대한 해결책은 다음과 같습니다.

<img src="image.png?nocache=<?php echo time(); ?>">

기본적으로 Unix 타임 스탬프를 추가하여 매개 변수를 동적으로 만들고 캐시가 없도록하면 작동했습니다.

그러나 내 문제는 약간 달랐습니다. 나는 즉시 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 ()은 파일 수정 시간을 가져옵니다.

Your problem is that despite the Expires: header, your browser is re-using its in-memory copy of the image from before it was updated, rather than even checking its cache.

I had a very similar situation uploading product images in the admin backend for a store-like site, and in my case I decided the best option was to use javascript to force an image refresh, without using any of the URL-modifying techniques other people have already mentioned here. Instead, I put the image URL into a hidden IFRAME, called location.reload(true) on the IFRAME's window, and then replaced my image on the page. This forces a refresh of the image, not just on the page I'm on, but also on any later pages I visit - without either client or server having to remember any URL querystring or fragment identifier parameters.

I posted some code to do this in my answer here.

Add a time stamp <img src="picture.jpg?t=<?php echo time();?>">

will always give your file a random number at the end and stop it caching

With the potential for badly behaved transparent proxies in between you and the client, the only way to totally guarantee that images will not be cached is to give them a unique uri, something like tagging a timestamp on as a query string or as part of the path.

If that timestamp corresponds to the last update time of the image, then you can cache when you need to and serve the new image at just the right time.

I assume original question regards images stored with some text info. So, if you have access to a text context when generating src=... url, consider store/use CRC32 of image bytes instead of meaningless random or time stamp. Then, if the page with plenty of images is displaying, only updated images will be reloaded. Eventually, if CRC storing is impossible, it can be computed and appended to the url at runtime.

From my point of view, disable images caching is a bad idea. At all.

The root problem here is - how to force browser to update image, when it has been updated on a server side.

Again, from my personal point of view, the best solution is to disable direct access to images. Instead access images via server-side filter/servlet/other similar tools/services.

In my case it's a rest service, that returns image and attaches ETag in response. The service keeps hash of all files, if file is changed, hash is updated. It works perfectly in all modern browsers. Yes, it takes time to implement it, but it is worth it.

The only exception - are favicons. For some reasons, it does not work. I could not force browser to update its cache from server side. ETags, Cache Control, Expires, Pragma headers, nothing helped.

In this case, adding some random/version parameter into url, it seems, is the only solution.

Ideally, you should add a button/keybinding/menu to each webpage with an option to synchronize content.

To do so, you would keep track of resources that may need to be synchronized, and either use xhr to probe the images with a dynamic querystring, or create an image at runtime with src using a dynamic querystring. Then use a broadcasting mechanism to notify all components of the webpages that are using the resource to update to use the resource with a dynamic querystring appended to its url.

A naive example looks like this:

Normally, the image is displayed and cached, but if the user pressed the button, an xhr request is sent to the resource with a time querystring appended to it; since the time can be assumed to be different on each press, it will make sure that the browser will bypass cache since it can't tell whether the resource is dynamically generated on the server side based on the query, or if it is a static resource that ignores query.

The result is that you can avoid having all your users bombard you with resource requests all the time, but at the same time, allow a mechanism for users to update their resources if they suspect they are out of sync.

<!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>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top