Jump to content

MOD_REWRITE to deceive the browser's image caching


Pixrael
 Share

Recommended Posts

In order to deceive the browser images cache in a javascript image src update, I use this htaccess trick to force the browser to reload "new" image from the server, the number es a time() var.

I want that Apache rewrite this request:

/site/downloads/9VefFf6vstUR0q1ywzPgjXw4PfAgYqGp-1562618833.png

to this:

/site/downloads/9VefFf6vstUR0q1ywzPgjXw4PfAgYqGp.png

and this is my declaration in htaccess:

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteRule ^site/downloads/([a-zA-Z0-9]+)-([0-9]+)$ site/downloads/$1.png [R=302,NC,L]
</IfModule>

But I don't know if it well defined, or if the PW htaccess is in conflict with this configuration.. PW show me the 404 page and the server don't send the picture url back.

Any idea?

Link to comment
Share on other sites

I wouldn't do a 302 for the operation. This essentially doubles the amount of requests the browser needs to do for images and I'm not even sure if it would actually cache-bust anything. Rather rewrite the url only internally so apache serves the correct file under the incoming url with cache-busting.

  • Like 2
Link to comment
Share on other sites

That mod_rewrite route don't works.. but (for the records) the following trick works smoothly  ?

<FilesMatch "^([a-zA-Z0-9]+)-([0-9]+)\.png$">
    FileEtag None
    <ifModule mod_headers.c>
        Header Unset ETag
        Header Set Cache-Control "max-age=0, no-store, no-cache, must-revalidate"
        Header Set Pragma "no-cache"
        Header Set Expires "Thu, 1 Jan 1970 00:00:00 GMT"
    </ifModule>
</FilesMatch>

 

Link to comment
Share on other sites

@Pixrael A simpler approach that doesn't require any server-side adjustments at all would be to include the cache-busting parameter as a query variable instead. For example:

/site/downloads/9VefFf6vstUR0q1ywzPgjXw4PfAgYqGp.png?v=1562618833

I use something like this during development for my CSS / JS assets, so the browser downloads those anew for each request and I see all changes immediately ...

The browser will not use the cached image if the query string differs. This way you don't need to rewrite any URLs in Apache. I would also strongly advise not to go with the second approach (using HTTP-headers to disable caching), as this way the images can never be cached and reused, which means your site takes a major performance hit. Can I ask why you need to do this at all? If the browser has already loaded the image, why force it to load it again?

  • Like 1
Link to comment
Share on other sites

17 minutes ago, MoritzLost said:

I use something like this during development for my CSS / JS assets, so the browser downloads those anew for each request and I see all changes immediately ...

On a sidenote: You can also disable caching while Chrome inspector is open inside the settings:

devtools-disable-cache.PNG.ca6adfab6814e314e5b44ec056e78e0a.PNG

(of course, if you're testing with several other browsers plus mobile devices at the same time, the query-string approach is better)

  • Like 2
Link to comment
Share on other sites

@MoritzLost Thanks for your comments. The first thing I tried was this ?v=XXXX technique, but do not works 100%, at least in chrome (several days testing that) not always reload the file. I don't know why, maybe chrome use more aggressive approach to save bandwidth or for speed..

"why force it to load it again?" .. because this is a tool that generate a picture to download, the customer can modify the tool paramaters and regenerate the picture again infinitely.. I don't want to create new pictures each time the user click the generate button (to save disk space at server), my approach is to create only one picture per user session, and use the token value as file name, so the tool overwrite it each time the picture is regenerate. I use ajax for that and with the response I change the src attribute in an image element to display the result.. this is the reason why I need that image must be forced to download each time when I change the src attribute..

Oh, this description looks a little complicated.. I explain correctly?

  • Like 1
Link to comment
Share on other sites

@Pixrael Thanks, that makes perfect sense. Are you sure the query parameter doesn't work? It really should, since it's a different request and may return different results for some services. Maybe Chrome is employing some heuristics to determine that it's always the same image ... though it isn't in your case ... I don't know, sounds curious.

In any case, your HTTP-header method is probably the best approach for this scenario! Though you really only need the Cache-Control header; Expires, ETag and and Pragma are superfluous except for the most legacy of legacy browsers ?

@dragan Firefox Developer Edition master race! ? Though I don't always have the Developer Tools open while writing my templates, and as you said I frequently need to test on other devices, so I prefer the caching busting approach. I usually have a $config->theme_version parameter in my config that gets appended to each CSS / JS URL, this way I can also easily invalidate caches on live sites when I push an update. During development (coupled to $config->debug) I just append the current timestamp, so the parameter changes for each request.

  • Like 1
Link to comment
Share on other sites

A solution that I also thought was to send the generated image using base64 data in the response, but even though it served to display the result to the user, I need a fixed URL since the purpose of the tool is that once the image is the desired one, the user can import it into a third application using that URL, each image will be valid only for 24hr, after that it will be deleted from the server using cron jobs

Link to comment
Share on other sites

You could use a simple PHP script that serves the image with readfile() and set appropriate headers in that script.

Maybe setup a dummy PW page with URL-segments enabled (or use a plain old query string) that will act as a "gateway" to those images. If you don't need to have the exact same filename on each request (download), then you you could even create the filename dynamically each time with adding / injecting time() or microtime() to the filename PHP will create for you:

    header('Content-Disposition: attachment; filename="'.basename($file).'"');

 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...