Does a Cache Buster on an Image Url in CSS Cause an Extra Request

Does a cache buster on an image URL in CSS cause an extra request?

Yes it will cause a new request for the image. If it is ? the image will reload.

If you don't want to make new request use # in example

background: url(../img/sprite.png#version=20130205) no-repeat -75px -208px;

Cache busting via params

The param ?v=1.123 indicates a query string, and the browser will therefore think it is a new path from, say, ?v=1.0. Thus causing it to load from file, not from cache. As you want.

And, the browser will assume that the source will stay the same next time you call ?v=1.123 and should cache it with that string. So it will remain cached, however your server is set up, until you move to ?v=1.124 or so on.

Does anyone know of any issues using a querystring within a CSS file?

Unless the browser is seriously broken, there should be nothing wrong. Suppose you wanted to use a dynamic file, such as url('/layout.php?section=1') or something. Query strings are kind of required there, so if the browser didn't work it'd be broken quite badly.

How is a file served when requested in css :hover as a background image

Because hovering event is client-side. And once the image is loaded on first request browser might be caching it. So your handler is not executed on subsequent request.

Refresh image with a new one at the same url

What I ended up doing was having the server map any request for an image at that directory to the source that I was trying to update. I then had my timer append a number onto the end of the name so the DOM would see it as a new image and load it.

E.g.

http://localhost/image.jpg
//and
http://localhost/image01.jpg

will request the same image generation code but it will look like different images to the browser.

var newImage = new Image();
newImage.src = "http://localhost/image.jpg";
var count = 0;
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
newImage.src = "http://localhost/image/id/image" + count++ + ".jpg";
}
setTimeout(updateImage, 1000);
}

Will browser download image twice if it's used in both an image's src as well as a div's background-image?

Browsers are pretty smart when it comes to caching.It should only ask for it once.

Additionally when it asks the server for an image, it usually sends with the request for the image, a couple of headers that tell the server.. Hey, I want this image, but I got one already that has these attributes that you told me about it last time you sent it to me.

The server can then respond with a 200 meaning it's different content 304 meaning the one you have is the same, so I won't send it again, use the one you got..

One of these methods uses an ETAG header, but there are a few more.

Your server needs to support this, but most do.

Additionally, the interweb is made up of a bunch of caches, which will also look at these sort of header values and return stuff for you.. That's why the web scales so well ;-)

Force refresh of cached CSS data

TL;DR

  • Change the file name or query string
  • Use a change that only occurs once per release
  • File renaming is preferable to a query string change
  • Always set HTTP headers to maximize the benefits of caching

There are several things to consider and a variety of ways to approach this. First, the spec

What are we trying to accomplish?

Ideally, a modified resource will be unconditionally fetched the first time it is requested, and then retrieved from a local cache until it expires with no subsequent server interaction.

Observed Caching Behavior

Keeping track of the different permutations can be a bit confusing, so I created the following table. These observations were generated by making requests from Chrome against IIS and observing the response/behavior in the developer console.

In all cases, a new URL will result in HTTP 200. The important thing is what happens with subsequent requests.

+---------------------+--------------------+-------------------------+
| Type | Cache Headers | Observed Result |
+---------------------+--------------------+-------------------------+
| Static filename | Expiration +1 Year | Taken from cache |
| Static filename | Expire immediately | Never caches |
| Static filename | None | HTTP 304 (not modified) |
| | | |
| Static query string | Expiration +1 Year | HTTP 304 (not modified) |
| Static query string | Expire immediately | HTTP 304 (not modified) |
| Static query string | None | HTTP 304 (not modified) |
| | | |
| Random query string | Expiration +1 Year | Never caches |
| Random query string | Expire immediately | Never caches |
| Random query string | None | Never caches |
+---------------------+--------------------+-------------------------+

However, remember that browsers and web servers don't always behave the way we expect. A famous example: in 2012 mobile Safari began caching POST requests. Developers weren't pleased.

Query String

Examples in ASP.Net MVC Razor syntax, but applicable in nearly any server processing language.

...since some applications have traditionally used GETs and HEADs with
query URLs (those containing a "?" in the rel_path part) to perform
operations with significant side effects, caches MUST NOT treat
responses to such URIs as fresh unless the server provides an explicit
expiration time. This specifically means that responses from HTTP/1.0
servers for such URIs SHOULD NOT be taken from a cache.

Appending a random parameter to the end of the CSS URL included in your HTML will force a new request and the server should respond with HTTP 200 (not 304, even if it is hasn't been
modified).

<link href="normalfile.css?random=@Environment.TickCount" />

Of course, if we randomize the query string with every request, this will defeat caching entirely. This is rarely/never desirable for a production application.

If you are only maintaining a few URLs, you might manually modify them to contain a build number or a date:

@{
var assembly = Assembly.GetEntryAssembly();
var name = assembly.GetName();
var version = name.Version;
}

<link href="normalfile.css?build=@version.MinorRevision" />

This will cause a new request the first time the user agent encounters the URL, but subsequent requests will mostly return 304s. This still causes a request to be made, but at least the whole file isn't served.

Path Modification

A better solution is to create a new path. With a little effort, this process can be automated to rewrite the path with a version number (or some other consistent identifier).

This answer shows a few simple and elegant options for non-Microsoft platforms.

Microsoft developers can use a HTTP module which intercepts all requests for a given file type(s), or possibly leverage an MVC route/controller combo to serve up the correct file (I haven't seen this done, but I believe it is feasible).

Of course, the simplest (not necessarily the quickest or the best) method is to just rename the files in question with each release and reference the updated paths in the link tags.



Related Topics



Leave a reply



Submit