如何在Node.js Express中实现支持浏览器缓存的已有图片返回?
Got it, let's figure out how to add proper browser caching to your Express image route. This will make repeat requests load faster and reduce your server's bandwidth usage. Here's a step-by-step implementation tailored to your setup:
Core Implementation: Update getOptimizedImage with Caching Logic
We'll leverage HTTP cache headers (Cache-Control, ETag, Last-Modified) and handle 304 Not Modified responses to let browsers reuse cached images.
First, make sure you're using the promise-based fs methods for cleaner async/await code:
const fs = require('fs').promises; const path = require('path'); const sharp = require('sharp');
Then update your controller function:
async function getOptimizedImage(req, res) { const { options, basedir, dir, img } = req.params; // Define the path to your preprocessed/cached image const cachedImagePath = path.join(__dirname, '../path/to/your/cache/dir', options, basedir, dir, img); try { // Check if the cached image exists await fs.access(cachedImagePath); // Get file stats to generate cache headers const fileStats = await fs.stat(cachedImagePath); const lastModified = fileStats.mtime.toUTCString(); const etag = `"${fileStats.size}-${fileStats.mtime.getTime()}"`; // Set cache control: adjust max-age based on how often your images change // Example: 7 days (604800 seconds) – use longer for static images, shorter for dynamic ones res.setHeader('Cache-Control', 'public, max-age=604800'); res.setHeader('Last-Modified', lastModified); res.setHeader('ETag', etag); // Check if browser already has a valid cache const clientModifiedSince = req.headers['if-modified-since']; const clientEtag = req.headers['if-none-match']; if ( (clientModifiedSince && clientModifiedSince === lastModified) || (clientEtag && clientEtag === etag) ) { // Image hasn't changed – tell browser to use cache return res.sendStatus(304); } // Send the cached image if cache is stale or missing res.sendFile(cachedImagePath); } catch (err) { // Cached image doesn't exist – process with Sharp const originalImagePath = path.join(__dirname, '../path/to/your/original/images', basedir, dir, img); try { // Parse your options (adjust this based on how your :options param is structured) const [widthStr, heightStr] = options.split(','); const width = parseInt(widthStr.split('-')[1]); const height = parseInt(heightStr.split('-')[1]); // Process the image with Sharp const processedImage = await sharp(originalImagePath) .resize(width, height) .toBuffer(); // Create directory structure for cached image if needed await fs.mkdir(path.dirname(cachedImagePath), { recursive: true }); // Save processed image to cache await fs.writeFile(cachedImagePath, processedImage); // Set cache headers for the newly generated image too const newFileStats = await fs.stat(cachedImagePath); res.setHeader('Cache-Control', 'public, max-age=604800'); res.setHeader('Last-Modified', newFileStats.mtime.toUTCString()); res.setHeader('ETag', `"${newFileStats.size}-${newFileStats.mtime.getTime()}"`); // Send the processed image res.type('image/jpeg').send(processedImage); } catch (processingErr) { res.status(404).send('Image not found or failed to process'); } } }
Key Details Explained
Cache-ControlHeader:publicallows the image to be cached by browsers, CDNs, and other intermediate caches.max-age=604800sets the cache duration to 7 days (in seconds). Tweak this based on your image update frequency – use2592000for 30 days if images rarely change.
ETag&Last-Modified: These headers act as unique identifiers for the image version. When the browser re-requests the image, it sends these values back inIf-None-MatchandIf-Modified-Sinceheaders. If they match the server's current values, we return a304 Not Modifiedinstead of re-sending the image.- 304 Response: This tells the browser "your cached version is still valid" – it skips downloading the image entirely, saving bandwidth and speeding up load times.
Additional Tips
- Ensure Cache Directory Permissions: Make sure your Node.js process has write access to the cache directory you're using.
- Cache Invalidation: If you ever need to update an image, delete the corresponding cached file – the next request will reprocess and cache the new version. Alternatively, include a content hash in your image URLs (e.g.,
image/w-200/h-300/myimg-v2.jpg) to force browsers to fetch the new version. - MIME Types: If you support multiple image formats (PNG, WebP), adjust
res.type()to match the processed image's format.
内容的提问来源于stack exchange,提问作者spencerready
相关产品推荐
相关产品推荐

