Node.js服务器端AJAX结果缓存方案咨询:中间件及Varnish可行性
Great question! Let’s break this down into two clear parts to address both your middleware and Varnish questions:
Since you’re dealing with image data stored in MongoDB, you’ll want middleware that can handle both binary and text-based AJAX responses in memory. Here are two reliable options tailored to your use case:
apicache(Quick & Low-Code)
This lightweight middleware is purpose-built for caching API/AJAX responses, uses in-memory storage by default, and requires almost zero setup to get started. It handles binary data (like your MongoDB-stored images) seamlessly, and lets you define cache durations per route.Example implementation:
const apicache = require('apicache'); const cache = apicache.middleware; // Cache image GET requests for 10 minutes app.get('/api/images/:imageId', cache('10 minutes'), async (req, res) => { const image = await Image.findById(req.params.imageId); res.set('Content-Type', image.contentType); res.send(image.data); // apicache automatically caches this binary buffer });You can also customize cache keys (e.g., include query params or user IDs for personalized caching) and add
X-Cacheheaders to debug hit/miss rates.Custom Middleware with
lru-cache(Fine-Grained Control)
If you need tighter control over cache limits, eviction policies, or custom invalidation logic, uselru-cache(a popular Least Recently Used cache library) to build a custom middleware. This is ideal if you want to cap memory usage or add rules to invalidate cache when images are updated in MongoDB.Example:
const LRU = require('lru-cache'); // Configure cache: max 200 entries, 10-minute TTL const imageCache = new LRU({ max: 200, ttl: 600000 }); const cacheMiddleware = (req, res, next) => { const cacheKey = `${req.method}-${req.originalUrl}`; // Unique key for each request const cachedData = imageCache.get(cacheKey); if (cachedData) { res.set('X-Cache', 'HIT'); res.set('Content-Type', cachedData.contentType); return res.send(cachedData.buffer); } // Override res.send to cache the response before sending it const originalSend = res.send; res.send = function(data) { imageCache.set(cacheKey, { buffer: data, contentType: res.get('Content-Type') }); res.set('X-Cache', 'MISS'); originalSend.call(this, data); }; next(); }; // Apply middleware to your image route app.get('/api/images/:imageId', cacheMiddleware, async (req, res) => { const image = await Image.findById(req.params.imageId); res.set('Content-Type', image.contentType); res.send(image.data); });
Absolutely! Varnish can cache AJAX responses, but you’ll need to adjust its default configuration because AJAX requests often include headers like X-Requested-With: XMLHttpRequest that Varnish doesn’t cache by default.
Key Configuration Steps:
- Allow Caching for AJAX Headers: Update your VCL (Varnish Configuration Language) to recognize and cache requests with the
X-Requested-Withheader. - Ensure Valid Cache Headers: Make sure your Express backend returns
Cache-Controlheaders (e.g.,public, max-age=600) to tell Varnish how long to keep the cached response.
Example VCL snippet to enable AJAX caching:
sub vcl_recv { // Cache GET AJAX requests (adjust if you use POST for AJAX) if (req.method == "GET" && req.http.X-Requested-With == "XMLHttpRequest") { // Remove cookies only if responses are not user-specific // Keep cookies if you need per-user cached versions unset req.http.Cookie; return (hash); } } sub vcl_backend_response { // Enforce caching for AJAX responses if backend doesn't set headers if (bereq.http.X-Requested-With == "XMLHttpRequest") { set beresp.ttl = 10m; set beresp.http.Cache-Control = "public, max-age=600"; set beresp.http.X-Varnish-Cache = "Cached"; } }
Important Notes:
- If your AJAX responses are user-specific (e.g., authenticated users get unique images), don’t unset the
Cookieheader—Varnish will automatically use the cookie as part of the cache key to store separate versions for each user. - For compressed responses, add
Vary: Accept-Encodingto your backend headers so Varnish caches both gzipped and uncompressed versions.
内容的提问来源于stack exchange,提问作者Chong Lip Phang

