You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Service Worker 图片缓存异常:使用Image构造函数加载缓存图片时caches.match返回null

Troubleshooting caches.match() Returning Null for Cached Images in Service Workers

Hey there, let's walk through why your caches.match(event.request) might be returning null when you try to load cached images via an Image instance, and how to fix this issue step by step.

Common Causes & Fixes

1. Request URL Mismatch (The #1 Culprit)

Service Worker cache matching relies on exact URL matches—even tiny differences will break it. Check these details:

  • Protocol: Did you cache https://your-domain.com/img.jpg but the Image instance is requesting http://your-domain.com/img.jpg?
  • Query Parameters: If your image URL has versioning like img.jpg?v=2, but you cached the URL without the query string, the match will fail.
  • Trailing Slashes: A URL like /img/photo.jpg vs /img/photo.jpg/ (with trailing slash) are treated as distinct.

Quick Fix:
Print the URL of both the cached request and the Image request to compare:

// In your Service Worker's fetch event
console.log('Incoming request URL:', event.request.url);

// In your main script when creating the Image
const img = new Image();
console.log('Image request URL:', img.src);

If query parameters are the issue, use the ignoreSearch option in caches.match():

caches.match(event.request, { ignoreSearch: true })

2. Request Mode or Headers Mismatch

When you create an Image instance, cross-origin requests default to no-cors mode. If you cached the image using a cors mode request (e.g., via fetch() with mode: 'cors'), the request objects won't match because their mode properties differ.

Fix:
Either:

  • Cache images using the same mode as the Image request (add mode: 'no-cors' when fetching for cache), or
  • Use the ignoreVary option in caches.match() to bypass header-based mismatches:
    caches.match(event.request, { ignoreVary: true })
    

3. The Image Isn't Actually Cached

Double-check if the image exists in your cache storage:

  1. Open Chrome DevTools → Application tab → Cache Storage.
  2. Select your cache bucket and verify the target image URL is listed.

If it's missing, your caching logic might be flawed:

  • Ensure you're waiting for cache completion in the install event with event.waitUntil().
  • Verify that successful network responses are being cached (use networkResponse.clone() when calling cache.put(), since responses are one-time use).

Example of a reliable install-time cache:

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('image-cache-v1')
      .then((cache) => {
        return cache.addAll([
          '/assets/img/photo1.jpg',
          '/assets/img/photo2.jpg'
        ]);
      })
  );
});

4. Service Worker Isn't Active or Intercepting Requests

  • Check if your Service Worker is in the Activated state (DevTools → Application → Service Workers). If it's in "Waiting", skip waiting or refresh the page to activate it.
  • Ensure your fetch event is explicitly handling image requests. Use event.request.destination === 'image' to target only image requests:
    self.addEventListener('fetch', (event) => {
      if (event.request.destination === 'image') {
        event.respondWith(
          caches.match(event.request, { ignoreSearch: true })
            .then((cachedResponse) => {
              // Fall back to network if no cache exists
              return cachedResponse || fetch(event.request).then((networkResponse) => {
                caches.open('image-cache-v1').then((cache) => {
                  cache.put(event.request, networkResponse.clone());
                });
                return networkResponse;
              });
            })
        );
      }
    });
    

5. HTTPS/localhost Requirement

Service Workers only work over HTTPS (or localhost for development). If you're testing on an HTTP domain (not localhost), the Service Worker won't register, and caching won't work at all.

Final Working Example

Here's a complete flow that should resolve the issue:

  1. Service Worker Code:
// Install: Pre-cache images
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('image-cache-v1')
      .then((cache) => cache.addAll(['/img/avatar.jpg', '/img/banner.jpg']))
  );
});

// Activate: Clean up old caches (optional but recommended)
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.filter((name) => name !== 'image-cache-v1')
          .map((name) => caches.delete(name))
      );
    })
  );
});

// Fetch: Serve cached images, fall back to network
self.addEventListener('fetch', (event) => {
  if (event.request.destination === 'image') {
    event.respondWith(
      caches.match(event.request, { ignoreSearch: true })
        .then((cached) => cached || fetch(event.request).then((res) => {
          caches.open('image-cache-v1').then((cache) => cache.put(event.request, res.clone()));
          return res;
        }))
    );
  }
});
  1. Main Script Code:
// Register Service Worker first
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then((reg) => console.log('Service Worker registered:', reg))
      .catch((err) => console.log('Service Worker registration failed:', err));
  });
}

// Create Image instance with cached URL
const img = new Image();
img.src = '/img/avatar.jpg'; // Exact match to cached URL (or use ignoreSearch if needed)
img.onload = () => document.body.appendChild(img);

内容的提问来源于stack exchange,提问作者Dion Zac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:12:50