iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🕌

Using Cloudflare's Purge by Single-File API for Advanced Cache Key Configurations

に公開

Introduction

This article provides notes on how to use the Cloudflare CDN Purge by single-file (URL) functionality via API.

While Instant Purge for a single file (URL) can be performed from the dashboard (available for all plans),

it cannot be used for the following cases:

The way to purge these requests by single file is by using API calls.

Changes to the cache key are made via Cache rules.
Therefore, we will look at how to perform purges via API according to those settings below.

API Usage Examples

Case: Purging by URL only

Default Cache Key

A single-file purge equivalent to the dashboard requires a body specified as follows.
In the case of the dashboard, you are only inputting the value of this URL.
First, let's look at a URL without a query string.

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# Caching in Cloudflare

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT

# Execute Purge via API

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'"}
    ]
}'

# Purge successful as cache becomes MISS

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: MISS

If the request has a query string, by default, the query string is included in the cache key.
To purge, specify the URL including the target query string.

{
    "files": [
        {"url": "https://www.example.com/foo?id=1"}
    ]
}
log
# Cache query string 1

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache query string 2

http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge query string 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET?id=1"'"}
    ]
}'

# Query string 2 is Hit

http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Query string 1 is Miss (Purge successful)

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

If there are multiple query strings, different orders like a=0&b=1 and b=1&a=0 are treated as different cache keys.
Specifying as follows will only purge the former.
To purge the latter, specify b=1&a=0.

{
    "files": [
        {"url": "https://www.example.com/foo?a=0&b=1"}
    ]
}
log
# Cache query string 1

http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache query string 2

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge query string 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET?a=0&b=1"'"}
    ]
}'

# Query string 2 is Hit

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Query string 1 is Miss (Purge successful)

http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

Changing Cache Keys with Cache Rules

Now, let's change the default cache keys.

Query String Sort 📖


When the query string is sorted, different orders like a=0&b=1 and b=1&a=0 become the same cache key.
It will be purged regardless of which one you specify.

{
    "files": [
        {"url": "https://www.example.com/foo?a=0&b=1"}
    ]
}
log
# Cache query string 1

http -h "$TARGET?a=0&b=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

# Query string 2 is also returned from the same cache

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge query string 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET?a=0&b=1"'"}
    ]
}'

# Query string 2 is MISS (Purge successful)

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: MISS
Ignore Query String 📖


When ignoring query strings, perform the purge without specifying a query string.
It will be purged even if you attach an arbitrary query string.

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# Cache query string 1

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Query string 2 is also returned from the same cache

http -h "$TARGET?id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge URL

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'"}
    ]
}'

# Query string 1 is MISS (Purge successful)

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

# Ignored and purged even if you attach an arbitrary query string

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET?hoge=2345"'"}
    ]
}'

http -h "$TARGET?id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS

Case: Purging by specifying URL + Headers

Requests with headers that are included in the cache key by default

Purge cache containing headers that are included in the cache key by default.

Request Header
Origin
X-Forwarded-Host
X-Host
X-Forwarded-Scheme
X-Original-URL
X-Rewrite-URL
Forwarded

In addition to the URL, add the relevant header and value to the headers field and issue the purge.
For example, to purge a cache of a request with an Origin header, it would look like this:

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"origin":"https://example.net"}}
    ]
}
log
# Cache Origin header 1

http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache Origin header 2

http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge Origin header 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"origin":"https://example.com"}}
    ]
}'

# Origin header 2 is Hit

http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT

# Origin header 1 is Miss (Purge successful)

http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS           

Changing Cache Keys with Cache Rules

Now, let's change the default cache keys.

Specified Request Header and Value 📖


Add the specified request header and its value to the cache key.
Perform the purge by including the header and value in the headers field.

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"z-id":"1"}}
    ]
}
log
# Cache header 1

http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache header 2

http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge header 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"z-id":"1"}}
    ]
}'

# Header 2 is Hit

http -h $TARGET z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT

# Header 1 is MISS (Purge successful)

http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS
Existence of Specified Request Header 📖


Use the existence of the specified request header in the cache key (boolean).
Perform the purge by setting the relevant header and a value (anything works).

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"z-id":"hoge"}}
    ]
}
log
# Cache header 1

http -h "$TARGET" z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS

# Header 2 is the same cache

http -h "$TARGET" z-id:2 | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge specified header (value is arbitrary)

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"z-id":"hoge"}}
    ]
}'

# Header 2 is MISS (Purge successful)
http -h "$TARGET" z-id:2 | grep -i cf-cache-status
CF-Cache-Status: MISS
Specified Cookie and Value 📖


Add the specified Cookie and its value to the cache key.
Perform the purge by including the Cookie and value in the headers field.

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=1"}}
    ]
}
log
# Cache cookie 1

http -h "$TARGET" cookie:"z-id=1" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache cookie 2

http -h "$TARGET" cookie:"z-id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge cookie 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"cookie":"z-id=1"}}
    ]
}'

# Cookie 2 is HIT

http -h "$TARGET" cookie:"z-id=2" | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cookie 1 is MISS (Purge successful)

http -h "$TARGET" cookie:"z-id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
Existence of Specified Cookie 📖

Use the existence of the specified Cookie in the cache key (boolean).
Perform the purge by setting the Cookie and a value (anything works).

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=hoge"}}
    ]
}
log
# Cache cookie 1

http -h "$TARGET" cookie:z-id=1 | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge specified cookie (value is arbitrary)

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"cookie":"z-id=hoge"}}
    ]
}'

# Cookie 2 is MISS (Purge successful)

http -h "$TARGET" cookie:z-id=1 | grep -i cf-cache-status
CF-Cache-Status: MISS
Device type 📖


Or

Set only one of them

An error will occur if you try to set both.

API Setting Location

This is the output from the Cache rules API.

# When set via toggle
   {
        "action": "set_cache_settings",
        "action_parameters": {
          "cache": true,
          "cache_key": {
            "cache_by_device_type": true
          }
        },

# When set via checkbox
   {
        "action": "set_cache_settings",
        "action_parameters": {
          "cache": true,
          "cache_key": {
            "custom_key": {
              "user": {
                "device_type": true
              }
            }
          }
        },
Headers added during origin forwarding

Regardless of the method, the following header is added to requests to the origin server.

# One of desktop, mobile, tablet
Cf-Device-Type: desktop

Add the device type determined by Cloudflare to the cache key.
It is classified into 3 types based on User agent and added to the cf-device-type header.
Perform the purge by specifying cf-device-type and its type in headers.

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cf-device-type":"mobile"}}
    ]
}
log
# Cache user-agent 1

http -h $TARGET user-agent:$ANDROID | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache user-agent 2

http -h $TARGET user-agent:$WINDOWS | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge device type mobile

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"cf-device-type":"mobile"}}
    ]
}'

# User-agent 2 is HIT

http -h $TARGET user-agent:$WINDOWS | grep -i cf-cache-status
CF-Cache-Status: HIT

# User-agent 1 is MISS (Purge successful)

http -h $TARGET user-agent:$ANDROID | grep -i cf-cache-status
CF-Cache-Status: MISS
Country 📖


Add the country code (2 letters) of the client seen by Cloudflare to the cache key cf-ipcountry.
Perform the purge by specifying cf-ipcountry in headers, but note that the country code must be specified in uppercase.

About the cf-ipcountry header

Cf-Ipcountry is one of the headers notified to the origin by default.

Cf-Ipcountry: JP

You can also verify it in HTTP logs.
Example of Instant logs

As an aside, you can get other information by using this.

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cf-ipcountry":"JP"}}
    ]
}
log
# Cache request from Japan

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache request from Australia

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge country code JP

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"cf-ipcountry":"JP"}}
    ]
}'

# Request from Australia is HIT

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: HIT

# Request from Japan is MISS (Purge successful)

http -h $TARGET | grep -i cf-cache-status
CF-Cache-Status: MISS
Language 📖


Use the value of the request header accept-language in the cache key.
Perform the purge by including accept-language and its value in the headers field.
The value is a strict case-sensitive match with the request.
In the case below, a request with 'ja' is effective, but 'Ja' will not match.

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"accept-language":"ja"}}
    ]
}
log
# Cache accept-language:ja

http -h $TARGET accept-language:ja | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache accept-language:de

http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge accept-language:ja

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"accept-language":"ja"}}
    ]
}'

# accept-language:de is HIT

http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT

# accept-language:ja is MISS (Purge successful)

http -h $TARGET accept-language:ja | grep -i cf-cache-status
CF-Cache-Status: MISS

# The case of the specified value must match the request header
# It will not be effective if it does not match the request header

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'", "headers": {"accept-language":"DE"}}
    ]
}'

http -h $TARGET accept-language:de | grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache key changes with case sensitivity

http -h $TARGET accept-language:ja-jp | grep -i cf-cache-status
CF-Cache-Status: HIT

http -h $TARGET accept-language:ja-Jp | grep -i cf-cache-status
CF-Cache-Status: MISS

Other

Changing Cache Keys with Cache Rules

Host Header 📖


Rewrite the host header during origin connection.
Use this rewritten host header in the cache key.
I am currently looking for a way to purge by single file.
As an alternative, I have confirmed that purge is possible by host name instead of single file.

{
    "hosts": [
        "o1.oymk.work"
    ]
}
How to rewrite the Host header

You can rewrite the host header with Origin rules.
The following rewrites the host header depending on the cookie value.

log
# Cache Origin 1

http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: HIT

# Cache Origin 2

http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: MISS

http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: HIT

# Received at the origin side with a different host name

o1.oymk.work - "GET /custom/ts.bin HTTP/2.0" 200 3 "-" "HTTPie/3.2.4" 
o2.oymk.work - "GET /custom/ts.bin HTTP/2.0" 200 3 "-" "HTTPie/3.2.4"

# Purge Origin 1

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "hosts": [
        "o1.oymk.work"
    ]
}'

# Origin 2 is HIT

http -h $TARGET cookie:"o=2"| grep -i cf-cache-status
CF-Cache-Status: HIT

# Origin 1 is MISS (Purge successful)

http -h $TARGET cookie:"o=1"| grep -i cf-cache-status
CF-Cache-Status: MISS
Origin Header 📖

Remove the origin header from the cache key.
Perform the purge without specifying the origin header.

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# Cache at Origin 1

http -h $TARGET origin:https://example.com | grep -i cf-cache-status
CF-Cache-Status: MISS

# Origin 2 is the same cache

http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: HIT

# Purge without specifying origin

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'"}
    ]
}'

# Origin 2 is MISS (Purge successful)
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: MISS
Cache deception armor 📖

Even when Cache deception armor is enabled, purge is issued against the default URL.

About Cache deception armor

See this blog

Enable Origin Cache Control as well

To enable Cache detection armor, enable Origin Cache Control.

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# File extension of the request does not match the Content-Type of the response

GET /deception/foo.jpg HTTP/1.1

# Because the response from the origin for jpg is application/json
# BYPASS by Cache deception armor
# - It would be cached if Cache deception armor were disabled

HTTP/1.1 200 OK
CF-Cache-Status: BYPASS
Content-Type: application/json; charset=utf-8

# File extension of the request matches the Content-Type of the response

GET /deception/foo.png HTTP/1.1

# Because the response from the origin for png is image/png
# Cache and HIT

HTTP/1.1 200 OK
CF-Cache-Status: HIT
Content-Type: image/png

# Purge png by URL

curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
    "files": [
        {"url": "'"$TARGET"'"}
    ]
}'

# Changes to MISS (Purge successful)

HTTP/1.1 200 OK
CF-Cache-Status: MISS

Conclusion

I have confirmed that Purge by single-file (URL) via API is possible. I did not demonstrate cases where multiple URLs (files) are specified or multiple items are added to the cache key, but they would follow the form shown in the API examples.

Regarding purge via Cloudflare Workers' fetch API and cache API, there is an explanation here.
I hope to try that separately.

Discussion