🕌

Purge by single-file を API から利用する(ダッシュボードでできない部分の対応)

に公開

はじめに

Cloudflare CDN キャッシュの Purge by single-file(URL)について、API で操作する場合の利用例をメモしておきます。

シングルファイル(URL)の Purge はダッシュボードから実施できるのですが(全プラン)、

下記のような場合は Purge できません。

これらのリクエストをシングルファイル Purge する方法は API コールになります。

キャッシュキーの変更は Cache rules から行います。
そのため、以下でその設定に応じた API での Purge 方法を見ていきます。

API 利用例

URL のみの指定で Purge するケース

デフォルトのキャッシュキー

ダッシュボード同等のシングルファイルパージは下記のようなボディを指定します。
ダッシュボードの場合、この url の値だけを入力していることになります。
まずはクエリーストリングがない URL です。

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# Cloudflare でキャッシュ中

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

# API から Purge 実行

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"'"}
    ]
}'

# キャッシュ MISS となり Purge 成功

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

リクエストにクエリーストリングがついている場合、デフォルトではクエリーストリングをキャッシュキーに含みます。
Purge も対象のクエリーストリング込みで url に指定して実行します。

{
    "files": [
        {"url": "https://www.example.com/foo?id=1"}
    ]
}
log
# クエリーストリング 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

# クエリーストリング 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

# クエリーストリング 1 を Purge

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"'"}
    ]
}'

# クエリーストリング 2 は Hit

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

# クエリーストリング 1 は Miss(Purge 成功)

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

複数のクエリーストリングがある場合、a=0&b=1b=1&a=0 のような順番違いは違うキャッシュキーで扱われます。
下記のように指定すると、前者だけ Purge されます。
後者を Purge するには b=1&a=0 を指定します。

{
    "files": [
        {"url": "https://www.example.com/foo?a=0&b=1"}
    ]
}
log
# クエリーストリング 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

# クエリーストリング 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

# クエリーストリング 1 を Purge

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"'"}
    ]
}'

# クエリーストリング 2 は Hit

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

# クエリーストリング 1 は Miss(Purge 成功)

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

Cache rules でキャッシュキーを変更

デフォルトのキャッシュキーを変更していきます。

クエリーストリングをソート 📖


クエリーストリングがソートされ a=0&b=1b=1&a=0 のような順番違いは同じキャッシュキーになります。
a=0&b=1b=1&a=0どちらで指定しても同じように Purge されます。

{
    "files": [
        {"url": "https://www.example.com/foo?a=0&b=1"}
    ]
}
log
# クエリーストリング 1 をキャッシュ

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

# クエリーストリング 2 も同じキャッシュから返信

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

# クエリーストリング 1 を Purge

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"'"}
    ]
}'

# クエリーストリング 2 が MISS(Purge 成功)

http -h "$TARGET?b=1&a=0" | grep -i cf-cache-status
CF-Cache-Status: MISS
クエリーストリングを無視 📖


クエリーストリングを無視する場合、Purge もクエリーストリングを指定せず実行します。
任意のクエリーストリングをつけたとしても Purge されます。

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# クエリーストリング 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

# クエリーストリング 2 も同じキャッシュから返信

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

# URL を Purge

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"'"}
    ]
}'

# クエリーストリング 1 が MISS(Purge 成功)

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

# 適当なクエリーストリングをつけても無視され Purge される

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

URL + Headers の指定で Purge するケース

標準でキャッシュキーの対象になるヘッダーをもつリクエスト

デフォルトでキャッシュキーに入るヘッダーをもったキャッシュを Purge します。

リクエストヘッダー
Origin
X-Forwarded-Host
X-Host
X-Forwarded-Scheme
X-Original-URL
X-Rewrite-URL
Forwarded

url に加え、 headers に当該のヘッダーと値を追加して Purge を発行します。
例えば Origin ヘッダー付きのリクエストのキャッシュを Purge する場合は下記のようになります。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"origin":"https://example.net"}}
    ]
}
log
# Origin ヘッダー 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

# Origin ヘッダー 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

# Origin ヘッダー 1 を Purge

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 ヘッダー 2 は Hit

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

# Origin ヘッダー 1 は Miss(Purge 成功)

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

Cache rules でキャッシュキーを変更

デフォルトのキャッシュキーを変更していきます。

指定のリクエストヘッダーと値 📖


指定のリクエストヘッダーとその値をキャッシュキーに追加します。
Purge も headers に当該ヘッダーと値を格納して実行します。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"z-id":"1"}}
    ]
}
log
# ヘッダー 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

# ヘッダー 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

# ヘッダー 1 を Purge

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"}}
    ]
}'

# ヘッダー 2 は Hit

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

# ヘッダー 1 は MISS (Purge 成功)

http -h $TARGET z-id:1 | grep -i cf-cache-status
CF-Cache-Status: MISS
指定のリクエストヘッダーの存在 📖


指定のリクエストヘッダーが存在することをキャッシュキーに使用します(boolean)。
当該ヘッダーと値(何でもよい)を設定し Purge を実行します。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"z-id":"hoge"}}
    ]
}
log
# ヘッダー 1 を キャッシュ

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

# ヘッダー 2 も同じキャッシュ

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

# 指定のヘッダー(値は任意)を Purge

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"}}
    ]
}'

# ヘッダー 2 が MISS (Purge 成功)
http -h "$TARGET" z-id:2 | grep -i cf-cache-status
CF-Cache-Status: MISS
指定の Cookie と値 📖


指定の Cookie とその値をキャッシュキーに加えます。
Purge も headers で当該の Cookie と値を格納し実行します。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=1"}}
    ]
}
log
# クッキー 1 を キャッシュ

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

# クッキー 2 を キャッシュ

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

# クッキー 1 を Purge

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"}}
    ]
}'

# クッキー 2 は HIT

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

# クッキー 1 は MISS(Purge 成功)

http -h "$TARGET" cookie:"z-id=1" | grep -i cf-cache-status
CF-Cache-Status: MISS
指定の Cookie の存在 📖

指定の Cookie が存在することをキャッシュキーに使用します(boolean)。
当該 Cookie と値(何でもよい)を設定し Purge を実行します。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cookie":"z-id=hoge"}}
    ]
}
log
# クッキー 1 をキャッシュ

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

# 指定のクッキー(値は任意)を Purge

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"}}
    ]
}'

# クッキー 2 が MISS(Purge 成功)

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


または

どっちかだけ設定する

両方設定しようとするとエラーになります。

API での設定箇所

Cache rules API での出力です。

# トグル指定時
   {
        "action": "set_cache_settings",
        "action_parameters": {
          "cache": true,
          "cache_key": {
            "cache_by_device_type": true
          }
        },

# チェックボックス指定時
   {
        "action": "set_cache_settings",
        "action_parameters": {
          "cache": true,
          "cache_key": {
            "custom_key": {
              "user": {
                "device_type": true
              }
            }
          }
        },
オリジン転送時に追加されるヘッダー

どちらの方式でもオリジンサーバーへのリクエストには下記のヘッダーが追加されます。

# desktop, mobile, tablet のどれか
Cf-Device-Type: desktop

Cloudflare が判断するデバイスタイプをキャッシュキーに追加します。
User agent により 3 種に分類し cf-device-type ヘッダーに追加されます。
Purge も headers に cf-device-type とそのタイプを指定します。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cf-device-type":"mobile"}}
    ]
}
log
# ユーザーエージェント 1 を キャッシュ

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

# ユーザーエージェント 2 を キャッシュ

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

# デバイスタイプ mobile を Purge

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"}}
    ]
}'

# ユーザーエージェント 2 は HIT

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

# ユーザーエージェント 1 は MISS(Purge 成功)

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


Cloudflare が見たクライアントの国コード(2 文字)をキャッシュキーに追加します cf-ipcountry
Purge は headers で cf-ipcountry を指定しますが、国コードは大文字で指定する必要がありました。

cf-ipcountry ヘッダーについて

Cf-Ipcountry は標準でオリジンに通知されるヘッダーの一つです。

Cf-Ipcountry: JP

HTTP ログで確認することも可能です。
Instant logs の例

余談ですが、これを使うと他の情報も色々取れます。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"cf-ipcountry":"JP"}}
    ]
}
log
# 日本からのリクエストをキャッシュ

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

# オーストラリアからのリクエストを キャッシュ

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

# 国コード JP を Purge

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"}}
    ]
}'

# オーストラリアからのリクエストは HIT

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

# 日本からのリクエストは MISS(Purge 成功)

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


リクエストヘッダー accept-language の値をキャッシュキーに利用します。
Purge も headers に accept-language とその値を格納します。
値はリクエストの大文字・小文字との完全マッチになります。
下記の場合リクエストが ja は効くが、Ja のときはマッチしません。

{
    "files": [
        {"url": "https://www.example.com/foo", "headers": {"accept-language":"ja"}}
    ]
}
log
# accept-language:ja をキャッシュ

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

# accept-language:de をキャッシュ

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

# accept-language:ja を Purge

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 は HIT

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

# accept-language:ja は MISS(Purge 成功)

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

# 指定する値の大文字・小文字はリクエストヘッダーと合わせる
# リクエストヘッダーとあっていないと効かない

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

# 大文字・小文字でキャッシュキーが変わる

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

その他

Cache rules でキャッシュキーを変更

Host ヘッダー 📖


オリジン接続時にホストヘッダーを書き換えます。
この書き換えたホストヘッダーをキャッシュキーに利用します。
シングルファイルでの Purge 方法は探し中です。
代案としてシングルファイルでなくホスト名指定で Purge 可能なことは確認しました。

{
    "hosts": [
        "o1.oymk.work"
    ]
}
ホストヘッダーの書き換え方

ホストヘッダーは Origin rules で書き換えることができます。
下記は cookie の値によってホストヘッダーを書き換えています。

log
# 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

# 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

# オリジン側では異なるホスト名で受信している

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"

# オリジン 1 を Purge

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"
    ]
}'

# オリジン 2 は HIT

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

# オリジン 1 は MISS(Purge 成功)

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

オリジンヘッダーをキャッシュキーから抜きます。
Purge もオリジンヘッダーを指定しないで実行します。

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# オリジン 1 でキャッシュ

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

# オリジン 2 も同じキャッシュ

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

# オリジン指定せず Purge

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"'"}
    ]
}'

# オリジン 2 が MISS(Purge 成功)
http -h $TARGET origin:https://example.net | grep -i cf-cache-status
CF-Cache-Status: MISS
Cache deception armor 📖

Cache deception armor が有効なときでも Purge はデフォルトの URL に対して発行します。

Cache deception armor について

こちらの blog

Origin Cache Control も有効に

Cache detection armor を有効にするには Origin Cache Control を有効にします。

{
    "files": [
        {"url": "https://www.example.com/foo"}
    ]
}
log
# リクエストのファイル拡張子とレスポンスのコンテントタイプが一致しない

GET /deception/foo.jpg HTTP/1.1

# jpg に対してオリジンから application/json の応答のため
# Cache deception armor で BYPASS
# ‐ Cache deseption armor 無効だとキャッシュされる

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

# リクエストのファイル拡張子とレスポンスのコンテントタイプが一致する

GET /deception/foo.png HTTP/1.1

# png に対してオリジンから image/png の応答のため
# Cache し HIT

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

# URL で png を Purge

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"'"}
    ]
}'

# MISS に変わる(Purge 成功)

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

さいごに

API でのシングルファイル(URL)の Purge ができることを確認しました。
URL(files)を複数指定したり、キャッシュキーに複数項目を追加するような場合は示しませんでしが、API の例にあるような形になります。

なお Cloudflare Workers の fetch APIcache API での Purge についてはこちらに説明があります。
別途試せたらと思います。

Discussion