Here is a 2024 update on handling this situation that I've used to organize and address some of the answers and comments on this question.
Client Side Solutions
Assume you have:
var url = 'http://website.com/20.jpg'
The easiest way to handle this if you have no control over the server is:
var date = encodeURI(new Date())
img.src = `${url}?${date}`
The following will also usually work but has the (remote) possibility of collisions between equivalent random numbers. If you want to play it 100% safe, just use the first approach:
var rand = Math.random()
img.src = `${url}?${rand}`
Someone in the comments of Dan's answer suggested using Cache-Control: no-cache for client side requests. Unfortunately, there are two problems with this approach:
- It requires the server to have reliably implemented the
If-Modified-Since and If-None-Match request headers, as explained in this answer.
- Even if the server has implemented these headers correctly (or even if you decide to go with the more robust
Cache-Control: no-store header that doesn't require those headers), there is no reliable way to tell the browser you want to use the Cache-Control header for image src requests, as explored in the answers to this question. If you are doing fetch requests, then, by all means, use the approach in this answer to set the Cache-Control header.
Server Side Solutions
If you have control over the server, you can set the Cache-Control header server side for requests. As explained above, if you want optimal caching, you need to implement If-Modified-Since and If-None-Match and use them alongside Cache-Control: no-cache. If you just want to eliminate caching altogether, you can simply set Cache-Control: no-store.
Here is how you could do that in Go:
func ServeMedia(w http.ResponseWriter, b []byte) {
w.Header().Set("Content-Type", "application/octet-stream")
// Eliminate caching so that reused image names will refresh.
w.Header().Set("Cache-Control", "no-store")
w.Write(b)
}