Resource caching strategy design
Resource Caching Strategy Design
Resource caching is one of the key methods to enhance application performance, effectively reducing duplicate requests and network transfer time by leveraging browser caching mechanisms. Caching strategies need to be tailored based on resource type, update frequency, and business requirements.
Browser Caching Mechanisms
Browser caching is primarily divided into two categories: strong caching and协商缓存 (negotiation caching):
- Strong Caching: Uses local copies directly without sending requests to the server. Controlled via
Cache-Control
andExpires
headers. - Negotiation Caching: Validates resource expiration with the server on each request, implemented through
Last-Modified/If-Modified-Since
orETag/If-None-Match
.
// Strong caching example - Setting Cache-Control
app.get('/static/js/main.js', (req, res) => {
res.setHeader('Cache-Control', 'public, max-age=31536000');
res.sendFile('/path/to/main.js');
});
// Negotiation caching example - Using ETag
app.get('/api/data', (req, res) => {
const data = getData();
const etag = generateETag(data);
if (req.headers['if-none-match'] === etag) {
return res.status(304).end();
}
res.setHeader('ETag', etag);
res.json(data);
});
Caching Strategy Classification
Static Resource Caching
Static resources like JS, CSS, and images typically adopt long-term caching strategies:
- Filenames with hash values:
main.a1b2c3d4.js
- Set long-term caching headers:
Cache-Control: public, max-age=31536000
<!-- Example of filenames with hashes -->
<script src="/static/js/main.a1b2c3d4.js"></script>
<link href="/static/css/styles.ef5g6h7i.css" rel="stylesheet">
Dynamic API Caching
API response caching requires more granular control:
- Short-term caching:
Cache-Control: max-age=60
- Private caching:
Cache-Control: private
- No caching:
Cache-Control: no-store
// API caching strategy example
app.get('/api/user/profile', (req, res) => {
// User profile data, cached for 1 minute and private only
res.setHeader('Cache-Control', 'private, max-age=60');
res.json(getUserProfile(req.user.id));
});
Service Worker Caching
Service Workers provide advanced caching control capabilities:
// Service Worker caching strategy example
const CACHE_NAME = 'v1';
const ASSETS = [
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
CDN Caching Configuration
CDN caching needs to align with origin server strategies:
- Edge node cache duration settings
- Cache key rules (ignoring query parameters, request headers, etc.)
- Cache refresh mechanisms
# Nginx CDN caching configuration example
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
add_header X-Cache-Status $upstream_cache_status;
}
Cache Update Strategies
Versioned Filenames
Precise cache updates via content hashing:
// Webpack configuration example
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js'
}
Cache Purge Techniques
- Query parameter versioning:
script.js?v=1.2.3
- Path versioning:
/v1.2.3/script.js
- Server-initiated CDN cache purges
Caching Strategy Practical Cases
Case 1: E-commerce Product Images
location ~* \.(jpg|jpeg|png|webp)$ {
# Long-term caching with version-based updates
expires 1y;
add_header Cache-Control "public";
# Fallback to CDN origin when images are missing
try_files $uri @cdn_fallback;
}
Case 2: Real-Time Data API
app.get('/api/stock/prices', (req, res) => {
// Real-time data, caching disabled
res.setHeader('Cache-Control', 'no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.json(getRealTimeStockData());
});
Cache Monitoring and Optimization
- Monitor cache hit rates
- Analyze user access patterns
- Adjust cache duration strategies
// Cache hit rate monitoring middleware
app.use((req, res, next) => {
const hit = res.getHeader('X-Cache-Hit');
statsd.increment(`cache.${hit ? 'hit' : 'miss'}`);
next();
});
Common Issue Solutions
Cache Pollution Issues
Solutions:
- Use
Vary
headers to handle content negotiation correctly - Avoid overusing query parameters as cache keys
# Proper handling of content negotiation
location /api/data {
proxy_cache_key "$scheme$request_method$host$uri$http_accept";
proxy_cache_valid 200 10m;
add_header Vary "Accept";
}
Mobile Caching Limitations
Mobile-specific handling:
- Appropriately shorten cache durations
- Consider local storage as a supplement
// Using localStorage as a cache fallback for mobile
function fetchWithCache(url) {
const cached = localStorage.getItem(`cache:${url}`);
if (cached) {
return Promise.resolve(JSON.parse(cached));
}
return fetch(url)
.then(res => res.json())
.then(data => {
localStorage.setItem(`cache:${url}`, JSON.stringify(data));
return data;
});
}
Advanced Caching Patterns
Cache-First Strategy
// Cache-first implementation
async function cacheFirst(request) {
const cached = await caches.match(request);
if (cached) return cached;
const response = await fetch(request);
const cache = await caches.open('v1');
cache.put(request, response.clone());
return response;
}
Network-First Strategy
// Network-first implementation
async function networkFirst(request) {
try {
const response = await fetch(request);
const cache = await caches.open('v1');
cache.put(request, response.clone());
return response;
} catch (e) {
return await caches.match(request);
}
}
Cache Security Considerations
- Avoid caching sensitive data
- Properly handle authenticated resources
- Prevent cache poisoning attacks
# Disable caching for sensitive data
location /api/account {
add_header Cache-Control "no-store, must-revalidate";
add_header Pragma "no-cache";
proxy_pass http://backend;
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:第三方脚本的优化加载
下一篇:关键渲染路径优化原则