ecabuk
ecabuk

Reputation: 1681

Caching JSON with Cloudflare

I am developing a backend system for my application on Google App Engine.

My application and backend server communicating with json. Like http://server.example.com/api/check_status/3838373.json or only http://server.example.com/api/check_status/3838373/

And I am planning to use CloudFlare for caching JSON pages.

Which one I should use on header? :

Content-type: application/json
Content-type: text/html

Is CloudFlare cache my server's responses to reduce my costs? Because I'll not use CSS, image, etc.

Upvotes: 12

Views: 20308

Answers (4)

mihnsen
mihnsen

Reputation: 425

By default, Cloudflare does not cache JSON file. I've ended up with config a new page rule:

https://example.com/sub-directiory/*.json*

  • Cache level: Cache Everything
  • Browser Cache TTL: set a timeout
  • Edge Cache TTL: set a timeout

Cloudflare page rule for json

Hope it saves someone's day.

Upvotes: 14

amit_saxena
amit_saxena

Reputation: 7624

You can cache your JSON responses on Cloudflare similar to how you'd cache any other page - by setting the Cache-Control headers. So if you want to cache your JSON for 60 seconds on the edge (s-maxage) and the browser (max-age), just set the following header in your response:

Cache-Control: max-age=60, s-maxage=60

You can read more about different cache control header options here:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

Please note that different Cloudflare plans have different value for minimum edge cache TTL they allow (Enterprise plan allows as low as 1 second). If your headers have a value lower than that, then I guess they might be ignored. You can see the limits here:

https://support.cloudflare.com/hc/en-us/articles/218411427-What-does-edge-cache-expire-TTL-mean-#summary-of-page-rules-settings

Upvotes: 1

Simon_Weaver
Simon_Weaver

Reputation: 146188

The new workers feature ($5 extra) can facilitate this:

Important point: Cloudflare normally treats normal static files as pretty much never expiring (or maybe it was a month - I forget exactly).

So at first you might think "I just want to add .json to the list of static extensions". This is likely NOT want you want with JSON - unless it really rarely changed - or is versioned by filename. You probably want something like 60 seconds or 5 minutes so that if you update a file it'll update within that time but your server won't get bombarded with individual requests from every end user.

Here's how I did this with a worker to intercept all .json extension files:

// Note: there could be tiny cut and paste bugs in here - please fix if you find!
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event));
});

async function handleRequest(event)
{
  let request = event.request;
  let ttl = undefined;
  let cache = caches.default;      
  let url = new URL(event.request.url);

  let shouldCache = false;


  // cache JSON files with custom max age
  if (url.pathname.endsWith('.json'))
  {
    shouldCache = true;
    ttl = 60;
  }

  // look in cache for existing item
  let response = await cache.match(request);

  if (!response) 
  {       
    // fetch URL
    response = await fetch(request);

    // if the resource should be cached then put it in cache using the cache key
    if (shouldCache)
    {
      // clone response to be able to edit headers
      response = new Response(response.body, response);

      if (ttl) 
      {
        // https://developers.cloudflare.com/workers/recipes/vcl-conversion/controlling-the-cache/
        response.headers.append('Cache-Control', 'max-age=' + ttl);
      }

      // put into cache (need to clone again)
      event.waitUntil(cache.put(request, response.clone()));
    }

    return response;
  }

  else {
    return response;
  }
}

You could do this with mime-type instead of extension - but it'd be very dangerous because you'd probably end up over-caching API responses.

Also if you're versioning by filename - eg. products-1.json / products-2.json then you don't need to set the header for max-age expiration.

Upvotes: 5

echtish
echtish

Reputation: 558

The standard Cloudflare cache level (under your domain's Performance Settings) is set to Standard/Aggressive, meaning it caches only certain types by default scripts, stylesheets, images. Aggressive caching won't cache normal web pages (ie at a directory location or *.html) and won't cache JSON. All of this is based on the URL pattern (e.g. does it end in .jpg?) and regardless of the Content-Type header.

The global setting can only be made less aggressive, not more, so you'll need to setup one or more Page Rules to match those URLs, using Cache Everything as the custom cache rule.

http://blog.cloudflare.com/introducing-pagerules-advanced-caching

BTW I wouldn't recommend using an HTML Content-Type for a JSON response.

Upvotes: 26

Related Questions