LoginSignup
0
0

More than 3 years have passed since last update.

AMPのキャッシュを消す with NodeJS

Last updated at Posted at 2019-05-28

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を追加

/etc/nginx/mime.types
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という想定(適宜変更)

amp-invalidate.js
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&amp_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 + '&amp_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とかかまして一括でやる場合の方が多い

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0