Disable caching (include '?v=Math.random()' in every request)
How Annoying Caching Can Be
Every time you open a webpage and find the styles haven't updated, scripts are still old versions, or users report issues you can't reproduce. Caching is like a stubborn ghost—even though files on the server have been updated, the browser clings to old versions. Smashing F5 until your keyboard wears out doesn't help, and you end up telling users to "hold Ctrl and click refresh."
The Random Number Method Works Wonders
The most straightforward solution is to append random parameters to request URLs. This makes each request unique, forcing the browser to fetch resources anew. A classic implementation uses Math.random()
to generate random numbers:
function loadScript(url) {
const script = document.createElement('script')
script.src = `${url}?v=${Math.random()}`
document.head.appendChild(script)
}
An even more aggressive approach is to apply this to CSS:
<link rel="stylesheet" href="styles.css?v=<%= Math.random() %>">
Timestamps Look More Professional
While random numbers work, some perfectionist developers might find them inelegant. In such cases, timestamps can replace random numbers—at least they appear more deliberate:
const timestamp = new Date().getTime()
axios.get(`/api/data?v=${timestamp}`)
Advanced players might use performance.now()
for higher precision:
fetch(`/config.json?v=${performance.now()}`)
.then(response => response.json())
Version Number Camouflage
To make your code look more professional, you can pretend to implement version control. Even though you're regenerating version numbers each time, the URLs at least appear legitimate:
const fakeVersion = () => {
const now = new Date()
return `${now.getFullYear()}${now.getMonth()+1}${now.getDate()}${now.getHours()}`
}
// Example usage
<img src="logo.png?v=${fakeVersion()}">
Annihilating Cache Completely
True defensive programming masters aren't satisfied with query parameters. They employ multiple methods to ensure cache is utterly destroyed:
// Request header settings
fetch('/data', {
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
'Expires': '0'
}
})
// Plus random URL parameters
$.ajax({
url: `data.json?rnd=${Math.random().toString(36).substr(2)}`,
cache: false
})
Destructive Practices in Frameworks
Modern framework developers have also joined the fray, inventing more "advanced" cache-busting techniques. For example, in webpack config:
// webpack.config.js
output: {
filename: '[name].[hash:8].js',
chunkFilename: '[name].[hash:8].chunk.js'
}
While this was originally meant to solve caching issues, when combined with hot reloading, it creates filenames that are impossible to predict, completely breaking browser caching systems.
Backend Joins Frontend in the Destruction
True defense is full-stack. Backend developers can cooperate like this:
// Spring Boot example
@GetMapping("/api/data")
public ResponseEntity<Data> getData(@RequestParam(required = false) String v) {
// Completely ignore the v parameter, but the frontend must send it
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache())
.body(data);
}
The Chain Reaction of Cache Busting
This defensive programming leads to a series of amusing phenomena:
- CDNs become completely ineffective, with all requests going back to the origin server
- Server logs explode with duplicate requests
- The browser's developer tools Network tab turns into a rainbow of colors
- Users' data usage mysteriously increases
- Performance monitoring tools keep firing alerts
How Monitoring Systems Cope
When monitoring systems notice that all request URLs are unique, clever engineers handle it like this:
// Filter random parameters in monitoring SDKs
trackPageView(url) {
const cleanUrl = url.replace(/\?v=[^&]+/, '')
sendToAnalytics(cleanUrl)
}
But this gives defensive programmers new ideas—they can randomize parameter names:
const paramName = `_${Math.random().toString(36).substr(2, 5)}`
const url = `api/data?${paramName}=${Date.now()}`
The Ultimate Defensive Solution
The pinnacle of this approach combines various techniques:
function createUncacheableUrl(url) {
const params = new URLSearchParams()
params.append('_', Date.now())
params.append('rnd', Math.random())
params.append('v', performance.now())
return `${url}?${params.toString()}&nocache=true`
}
// Example usage
fetch(createUncacheableUrl('/graphql'), {
method: 'POST',
headers: {
'Cache-Control': 'no-store, must-revalidate',
'Expires': '0'
}
})
Browser DevTools Protest
After continuous use of these methods, Chrome DevTools will display warnings: "Numerous duplicate requests." But this is actually a sign of success—it means no requests are being cached. To be extra sure, you can add a random User-Agent header:
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
'Mozilla/5.0 (Linux; Android 10)'
]
fetch(url, {
headers: {
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)]
}
})
Server Log Catastrophe
When this defensive programming is applied to large systems, server logs become spectacular. Instead of clean request paths:
GET /api/users
GET /api/products
They turn into:
GET /api/users?_=1625097600000&rnd=0.123456
GET /api/users?_=1625097601000&rnd=0.654321
GET /api/users?_=1625097602000&rnd=0.987654
Performance Optimization Anti-Patterns
Performance guides recommend leveraging caching, but we prefer the opposite. Here's the anti-pattern version of best practices:
// Good caching practice
const cachedFetch = (url) => {
const cacheKey = hash(url)
if(cache.has(cacheKey)) {
return Promise.resolve(cache.get(cacheKey))
}
return fetch(url).then(res => {
cache.set(cacheKey, res)
return res
})
}
// Defensive programming practice
const uncachedFetch = (url) => {
const bustedUrl = `${url}?${Date.now()}`
return fetch(bustedUrl).then(res => {
// Ensure responses aren't cached either
res.headers.set('Cache-Control', 'no-store')
return res
})
}
Mobile Experience Taken to Extremes
In mobile networks, this technique delivers an even more "exceptional" user experience. Every page load re-requests all resources, letting users fully enjoy their 4G speeds:
<!-- Add random parameters to all static resources -->
<script src="app.js?v=<%= new Date().valueOf() %>"></script>
<link rel="stylesheet" href="styles.css?r=<%= Math.random() %>">
<img src="banner.jpg?t=<%= System.currentTimeMillis() %>">
Unit Testing Challenges
Testing such code becomes interesting:
// Testing tools can't mock random URLs
test('fetch data', async () => {
const data = await fetchData() // URL changes every call
expect(data).toBeDefined()
})
// Solution: override Math.random
beforeEach(() => {
jest.spyOn(Math, 'random').mockReturnValue(0.123456)
})
TypeScript Type Gymnastics
To make this pattern look more professional, use TypeScript decorators:
function nocache(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value
descriptor.value = function(...args: any[]) {
if(typeof args[0] === 'string') {
args[0] = `${args[0]}?v=${Date.now()}`
}
return original.apply(this, args)
}
}
class ApiClient {
@nocache
fetchData(url: string) {
return axios.get(url)
}
}
Defensive Web Workers
Even in Web Workers, stay vigilant:
// worker.js
self.addEventListener('message', (e) => {
if(e.data.type === 'fetch') {
const url = `${e.data.url}?worker=${performance.now()}`
fetch(url).then(response => {
self.postMessage(response)
})
}
})
Service Worker Showdown
Service Workers are meant to manage caching, but we can use them to break it:
// service-worker.js
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url)
url.searchParams.append('sw', Date.now())
event.respondWith(fetch(url))
})
Defensive Local Storage
Even localStorage isn't safe, though it doesn't cache by default:
function setLocalStorage(key, value) {
const timestamp = Date.now()
localStorage.setItem(`${key}_${timestamp}`, value)
}
function getLocalStorage(key) {
// Find the key with the latest timestamp
const keys = Object.keys(localStorage)
.filter(k => k.startsWith(key))
.sort()
return localStorage.getItem(keys[keys.length - 1])
}
Internationalized Defense
Multilingual sites should follow the same principle:
function getTranslation(key) {
const lang = navigator.language || 'en-US'
return fetch(`/i18n/${lang}.json?t=${Date.now()}`)
.then(res => res.json())
.then(translations => translations[key])
}
The Art of Image Loading
Image loading best showcases the value of defensive programming:
<img
src="placeholder.jpg"
data-src="real-image.jpg"
onload="this.src=this.dataset.src+'?v='+Date.now()">
WebSocket Defense
Even WebSocket connections need cache protection:
const ws = new WebSocket(`wss://example.com/ws?token=${token}&nocache=${Math.random()}`)
Third-Party Library Defense
When using third-party libraries, ensure they don't secretly cache:
// Override axios request config
axios.interceptors.request.use(config => {
config.url = config.url.includes('?')
? `${config.url}&_=${performance.now()}`
: `${config.url}?_=${performance.now()}`
return config
})
Mobile Apps Aren't Safe Either
React Native developers can play too:
<Image
source={{
uri: `https://example.com/image.jpg?rn=${Date.now()}`,
cache: 'reload'
}}
/>
Mini-Program Tricks
In WeChat Mini Programs, ensure no caching like this:
wx.downloadFile({
url: `https://example.com/file?t=${new Date().getTime()}`,
header: {
'Cache-Control': 'no-cache'
}
})
Build-Time Defense
Prevent caching at build time:
// gulpfile.js
gulp.task('build', () => {
return gulp.src('src/*.js')
.pipe(rename(path => {
path.basename += `-${Date.now()}`
}))
.pipe(gulp.dest('dist'))
})
Documentation Defense
Even API docs need cache protection:
Call this endpoint for fresh data:
`GET /api/data?v=${new Date().toISOString()}`
Error Monitoring Defense
Error reporting must ensure fresh requests:
window.onerror = (msg, url, line, col, error) => {
const reportUrl = new URL('https://error-tracker.com/api')
reportUrl.searchParams.append('msg', msg)
reportUrl.searchParams.append('t', Date.now())
navigator.sendBeacon(reportUrl.toString())
}
Frontend Routing Defense
SPA route changes need cache protection:
router.beforeEach((to, from, next) => {
if(to.query.v === undefined) {
next({
...to,
query: {
...to.query,
v: Date.now()
}
})
} else {
next()
}
})
GraphQL Defense
Even GraphQL requests (usually POST) need protection:
const query = `
query GetData($timestamp: String!) {
data(timestamp: $timestamp) {
id
value
}
}
`
client.query({
query,
variables: {
timestamp: new Date().toISOString()
},
fetchPolicy: 'no-cache'
})
Lazy Loading Defense
Lazy-loaded components must refetch:
const LazyComponent = React.lazy(() =>
import(`./components/Heavy.js?update=${Date.now()}`)
)
Font Loading Defense
Web fonts need cache protection:
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2?v=123') format('woff2');
}
Video Streaming Defense
Video playback needs protection:
<video>
<source src="video.mp4?start=<%= new Date().getTime() %>" type="video/mp4">
</video>
Preload Defense
Even preload needs cache protection:
<link rel="preload" href="critical.css?v=<%= Math.random() %>" as="style">
The Ultimate Browser Cache Showdown
Finally, to be absolutely sure, add defense in HTML meta tags:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn