トップ «前の日記(2018-05-13) 最新 次の日記(2018-05-23)» 編集

2018-05-17 [長年日記]

_ NuxtデフォルトサーバはCache-Controlできないので注意

まとめ

  • Nuxtは各種のサーバサイドフレームワークと組み合わせられるがNuxtだけでもサーバとして機能する
  • デフォルトで ETag は吐くが Cache-Control は吐かないのでそのまま CDN に食わせるといつまでもリフレッシュされない
    • この影響を受けるのはあくまで vue-router を経由する Page だけ
    • assets に関しては nuxt start で serve している場合は問答無用で max-age は 1 year になる*1
  • optional な http response header を追加する middleware はどうもなさげ
    • 他のフレームワークと組み合わせてその middleware を使えば追加できる(Koa で確認済み)

そもそもWebのcacheって

  • private cache と public cache がある
  • CDN は public cache
  • ブラウザは private cache
  • Cache-Control を private にすると CDN は cache できない(したがって、リクエスト数も転送量も減らない)
  • とにかく Nuxt.js は何の情報も追加しない

※ public と private の話は恥ずかしながら CDN切り替え作業における、Web版メルカリの個人情報流出の原因につきまして - Mercari Engineering Blog にあるようにメルカリのやらかしで知りました。(ちなみに Rails はデフォルトで max-age=0, private, must-revalidate を付加するので特に何も考える必要なく CDN はスルーになる。)

CDN側では基本的にmax-ageを推奨してる

基本的には Cache-Control: max-age= を設定するのがよさげ。(Surrogate-Control や s-maxage だったりもしますが、細かいことは置いておく。)

しかし Nuxt.js にはサーバ側の設定の余地がない。(SSR用の MartinLG/nuxt-custom-headers: Nuxt module to add custom headers to SSR rendered pages. というものはある。)

NuxtではETagと304しか考えてない

具体的なコードは以下の部分。

lib/core/middleware/nuxt.js

  // Add ETag header
   if (!error && this.options.render.etag) {
     const etag = generateETag(html, this.options.render.etag)
     if (fresh(req.headers, { etag })) {
       res.statusCode = 304
       res.end()
       return
     }
     res.setHeader('ETag', etag)
   }

nuxt.config.js の render.etag option を見るこの辺以外に cache を考慮しているコードは存在しない。ETag を付けるか付けないかだけ。直接ブラウザとやりとりするならこれだけでも十分かもしれないが CDN を通す場合はそうはいかない。

そこでNode.jsのサーバサイドフレームワークと組み合わせる

nuxt-community/create-nuxt-app: Create Nuxt.js App in seconds.

を使えば Express, Koa, Hapi, ... などなどからフレームワークを選べる。これらの middleware で custom header を吐いてあげればおk

具体的に効果的にcacheするには

例えば Koa であれば

を組み合わせて、./server/index.js で

const Koa = require('koa')

const app = new Koa()

require('koa-ctx-cache-control')(app)

app.use(async (ctx, next) => {
  ctx.cacheControl('max-age=0')

こんな感じ。

こうすると pages 以下の component を serve する時には Cache-Control: max-age=0 が付加されたうえで ETag でのキャッシュ内容のチェックが行われるので、origin サーバから直接転送されるものはコンテンツの鮮度チェックはしつつも転送はほぼエッヂサーバから行われるので速い。(はず)

*1 cache buster の効くファイルが生成されている