Frontend Development 12 min read

API Failure Resilience Using CDN and IndexedDB Caching

The article presents a comprehensive strategy for handling API outages by storing data locally with IndexedDB, synchronizing updates through a CDN, and implementing Axios interceptors and Node‑based scheduled jobs to ensure seamless user experience without white‑screen failures.

政采云技术
政采云技术
政采云技术
API Failure Resilience Using CDN and IndexedDB Caching

Introduction

What happens if an API goes down? The page turns white. A simple, non‑intrusive solution is to cache the data locally.

Thought Process

Where to Store?

The first instinct is browser local storage, considering the four main storage options.

Feature Comparison

Feature

Cookie

localStorage

sessionStorage

IndexedDB

Data lifecycle

Can be set by server or client, has expiration

Persistent

Cleared when page is closed

Persistent

Storage size

4KB

5MB

5MB

Dynamic, >250MB

Server communication

Sent in every request header

None

None

None

Compatibility

All browsers

All browsers

All browsers

Not supported by IE, supported by other major browsers

Because the required data volume exceeds 5 MB, IndexedDB is chosen.

For new users or long‑inactive users, stale or missing cache data can be an issue, so the solution also leverages cloud storage and a CDN.

In summary: online CDN + offline IndexedDB.

Overall Solution

Overall Flowchart

CDN

First, a brief overview of the online CDN.

Usually the backend handles updates; the core issue is the update strategy, which is omitted here.

Another approach is to run a dedicated Node service that updates CDN data.

Flowchart

Hijacking Logic

All API calls are intercepted; the response status and cache tags are examined to decide whether to update data, fetch data, or apply a cache strategy.

A whitelist controls which APIs are cached.

axios.interceptors.response.use(
      async (resp) => {
        const { config } = resp
        const { url } = config
        // If a CDN tag exists and the API is whitelisted, update CDN
        if (this.hasCdnTag() && this.isWhiteApi(url)) {
          this.updateCDN(config, resp)
        }
        return resp;
      },
      async (err) => {
        const { config } = err
        const { url } = config
        // If the request matches the whitelist and cache is enabled, try CDN cache
        if (this.isWhiteApi(url) && this.useCache()) {
          return this.fetchCDN(config).then(res => {
            pushLog(`CDN cache hit, please handle`, SentryTypeEnum.error)
            return res
          }).catch(() => {
            pushLog(`CDN cache not synchronized, please handle`, SentryTypeEnum.error)
          })
        }
      }
    );

Cache Strategy

When the number of consecutive API errors reaches maxCount , the cache switch is turned on and will be turned off after expiresSeconds seconds.

The switch prevents network fluctuations from causing unwanted cache hits.

/*
* Cache strategy
*/
useCache = () => {
  if (this.expiresStamp > +new Date()) {
    const d = new Date(this.expiresStamp)
    console.warn(`
    ---------------------------------------
    Cache enabled
    Expiration time: ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}
    ---------------------------------------
    `)
    return true
  }
  this.errorCount += 1
  localStorage.setItem(CACHE_ERROR_COUNT_KEY, `${this.errorCount}`)
  if (this.errorCount > this.maxCount) {
    this.expiresStamp = +new Date() + this.expiresSeconds * 1000
    this.errorCount = 0
    localStorage.setItem(CACHE_EXPIRES_KEY, `${this.expiresStamp}`)
    localStorage.removeItem(CACHE_ERROR_COUNT_KEY)
    return true
  }
  return false
}

Unique Identifier

The combination of method , url , and data uniquely identifies an API request.

Dynamic identifiers such as timestamps can be filtered manually.

/**
 * Generate a unique cache key for an API request
 */
generateCacheKey = (config) => {
  const { method, url, data, params } = config;
  let rawData = ''
  if (method === 'get') {
    rawData = params
  }
  if (method === 'post') {
    rawData = JSON.parse(data)
  }
  return `${encodeURIComponent([method, url, stringify(rawData)].join('_'))}.json`;
};

Update Data

/**
 * Update CDN cache data
 */
updateCDN = (config, data) => {
  const fileName = this.generateCacheKey(config)
  const cdnUrl = `${this.prefix}/${fileName}`
  axios.post(`${this.nodeDomain}/cdn/update`, {
    cdnUrl,
    data
  })
}

Node Scheduled Task

A scheduled job uses puppeteer to visit the site with a cache tag and update CDN data.

import schedule from 'node-schedule';

const scheduleJob = {};

export const xxxJob = (ctx) => {
  const { xxx } = ctx.config;
  ctx.logger.info(xxx, 'xxx');
  const { key, url, rule } = xxx;
  if (scheduleJob[key]) {
    scheduleJob[key].cancel();
  }
  scheduleJob[key] = schedule.scheduleJob(rule, async () => {
    ctx.logger.info(url, new Date());
    await browserIndex(ctx, url);
  });
};

export const browserIndex = async (ctx, domain) => {
  ctx.logger.info('browser --start', domain);
  if (!domain) {
    ctx.logger.error('domain is empty');
    return false;
  }
  const browser = await puppeteer.launch({
    args: [
      '--use-gl=egl',
      '--disable-gpu',
      '--no-sandbox',
      '--disable-setuid-sandbox',
    ],
    executablePath: process.env.CHROMIUM_PATH,
    headless: true,
    timeout: 0,
  });
  const page = await browser.newPage();
  await page.goto(`${domain}?${URL_CACHE_KEY}`);
  await sleep(10000);
  // Click all tab items to trigger requests
  const list = await page.$$('.po-tabs__item');
  if (list?.length) {
    for (let i = 0; i < list.length; i++) {
      await list[i].click();
    }
  }
  await browser.close();
  ctx.logger.info('browser --finish', domain);
  return true;
};

Effect

Manually block the entire domain and the page still renders correctly.

IndexedDB

With CDN handling the online side, IndexedDB takes care of offline storage. For simple CRUD operations, the third‑party library localForage is sufficient.

axios.interceptors.response.use(
      async (resp) => {
        const { config } = resp
        const { url } = config
        if (this.hasCdnTag() && this.isWhiteApi(url)) {
          this.updateCDN(config, resp)
        }
        if (this.isIndexDBWhiteApi(url)) {
          this.updateIndexDB(config, resp)
        }
        return resp;
      },
      async (err) => {
        const { config } = err
        const { url } = config
        if (this.isWhiteApi(url) && this.useCache()) {
          return this.fetchCDN(config).then(res => {
            pushLog(`CDN cache hit, please handle`, SentryTypeEnum.error)
            return res
          }).catch(() => {
            pushLog(`CDN cache not synchronized, please handle`, SentryTypeEnum.error)
            if (this.isIndexDBWhiteApi(url)) {
              return this.fetchIndexDB(config).then(res => {
                pushLog(`IndexedDB cache hit, please handle`, SentryTypeEnum.error)
                return res
              }).catch(() => {
                pushLog(`IndexedDB cache not synchronized, please handle`, SentryTypeEnum.error)
              })
            }
          })
        }
      }
    );

Conclusion

Advantages: non‑intrusive to business code, low cost, and effectively prevents pure white‑screen scenarios. Disadvantages: limited applicability, not suitable for highly time‑sensitive data, and does not support IE.

The API resilience solution is still evolving; feedback and discussion are welcome.

Its purpose is to proactively prevent API service failures, reducing a P0 incident to P2/P3 or even making it invisible to users.

Two Requests

If you found this article helpful, please click "Watch" to increase its visibility and follow the "Zhengcai Cloud Technology" public account for more curated content.

Recruitment

The Zhengcai Cloud Technology team (Zero) in Hangzhou is a passionate, growth‑oriented front‑end team with over 80 members, averaging 27 years of age, many of whom are full‑stack engineers. We work on material systems, engineering platforms, intelligent platforms, performance, cloud applications, data analysis, error monitoring, and visualization, constantly exploring the front‑end technology frontier.

If you are interested in joining a dynamic team that values technical craftsmanship and impact, please reach out to [email protected] .

frontendCachingCDNAxiosAPIresilienceIndexedDB
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.