AMPのキャッシュを消すのが地味に面倒だったのでメモ
他の言語(PHP、Python)はあったけどNodeJSはなかったので実装した。
公式:https://developers.google.com/amp/cache/update-cache
参考1:https://beiznotes.org/amp-update-cache/
参考2:https://www.monotalk.xyz/blog/amp-%E3%81%AE-update-cache-%E8%A6%81%E6%B1%82%E3%82%92-apikeypub-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E9%80%81%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/
秘密鍵、公開鍵の作成が必要
# 公開鍵、秘密鍵を作成
$ openssl genrsa 2048 > private-key.pem
$ openssl rsa -in private-key.pem -pubout > public-key.pem
公開鍵(public-key.pem)は
https://{ドメイン}/.well-known/amphtml/apikey.pub
にリネームして格納、.well-known/amphtmlはフォルダがない場合は作る
apikey.pubはContent-Typeがtext/plain
形式でレスポンス返却するようにする
NginXの場合、/etc/nginx/mime.types
にpubのファイル拡張子のdefaultのContent-Typeを追加
types {
...中略
# 追加
text/plain pub;
}
curlコマンドでtext/plainで返却されているか検証する
$ curl -I https://example.com/.well-known/amphtml/apikey.pub
/var/www/amp-keys/private-key.pem
に秘密鍵をおいている前提、
ドメイン名はexample.com
という想定(適宜変更)
const axios = require('axios')
const fs = require('fs')
const crypto = require('crypto')
const program = require('commander')
// 環境変数
const DOMAIN = 'example.com'
// 秘密鍵のパス
const privateKeyPath = '/var/www/amp-keys/private-key.pem'
// AMPホスティングCDNのドメインを取得
async function getUpdateCacheApiDomainSuffix() {
const data = await axios.get('https://cdn.ampproject.org/caches.json').then(res => res.data)
const updateCacheApiDomainSuffixes = []
for (let cache of data.caches) {
updateCacheApiDomainSuffixes.push(cache.updateCacheApiDomainSuffix)
}
return updateCacheApiDomainSuffixes
}
// AMPUrlフォーマット:https://developers.google.com/amp/cache/overview#amp-cache-url-format
function AMPUrlFormat(url) {
return url.replace('-', '--').replace('.', '-')
}
async function main() {
program
.version('1.0.0')
.option('-p, --ampPath <ampPath>', 'ampPath')
.parse(process.argv)
const ampPath = program.ampPath
if (!ampPath) {
console.log('-p /amp/page')
return
}
const updateCacheApiDomainSuffixes = await getUpdateCacheApiDomainSuffix()
const ts = Math.floor(new Date().getTime() / 1000) // Unix秒(リクエスト時の60秒内に収めないといけない)
const privateKey = fs.readFileSync(privateKeyPath)
for (let updateCacheApiDomainSuffix of updateCacheApiDomainSuffixes) {
const AMP_BASE_URL = `https://${AMPUrlFormat(DOMAIN)}.${updateCacheApiDomainSuffix}`
const SIGNATURE_URL = `/update-cache/c/s/${DOMAIN}${ampPath}?amp_action=flush&_ts=`
// AMP CacheのURLのドメイン部を除去した文字列をダイジェスト値として、電子署名を生成
const url = SIGNATURE_URL + ts
const sign = crypto.createSign('RSA-SHA256')
sign.update(url)
// 生成した電子署名をbase64エンコードし、`amp_url_signature` として使う。
const signature = sign.sign(privateKey, 'base64')
// update-cache の要求URLを生成し、リクエスト送付
const ampUrl = AMP_BASE_URL + url + '&_url_signature=' + signature
console.log(ampUrl)
const result = await axios.get(ampUrl).then(res => res.data).catch(res => res.data)
// 成功するとOK、指定のCDNにない場合は404エラーになる
console.log(result)
}
}
main()
実行はつぎのように-p
オプションにampページのパスを指定
$ node amp-invalidate.js -p /amp/page
実際はsitemap.xmlとかかまして一括でやる場合の方が多い