本題
記事中の画像の取得に失敗することがある問題を解決してみました✨
このブログは、Notion API を通じて Notion で書いた記事を取得してレンダリングしているのですが、Notion に直接アップロードした画像の URL は1時間で有効期限が過ぎてしまうので、その場合は新しい URL を発行し直さないと画像が取得できません。
これは Next.js の強みの一つである SSG と相性が悪い問題です。
この問題を解決する方法としては、以下の5パターンほどが考えられます。
自分は、最初4を試してみて失敗した後、1と5の併用で解決することにしました。
- ページの ISR 対応を行う
- 記事の編集時、Notion に画像を直接アップロードするのではなく、外部のストレージにアップロード
- ビルド時、画像を別の無期限のストレージにコピーして、URL を差し替える
- ビルド時、画像を Public フォルダにコピーして、URL をローカルのパスに差し替える
- SWR を利用して、ユーザーがページを開いたとき、クライアントサイドで画像の取得処理を行う
ページの ISR 対応を行う
ISR とは、Incremental Static Regeneration の略で、指定した期間後にユーザーが該当ページにアクセスした段階で、サーバー側で更新処理を走らせる方法です。
今回は、サーバー側で Notion API など必要な処理を走らせ、画像URLなどの有効期限を更新させることになります。
ただこの方法だと、更新処理を発火させたユーザー本人は、更新された画像URLを取得することができず、有効期限が切れたURLの方で画像にアクセスことになってしまいます。
これは、更新処理が終わるまで古いキャッシュを返すという ISR の仕様から、仕方のないことのようです。
ISR は画像の更新対応だけでなく、Notion の記事を追加した際にも、半自動的にブログに更新内容を反映させる仕組みなので、今回の問題とは関係なく採用することにしています。
記事の編集時、Notion に画像を直接アップロードするのではなく、外部のストレージにアップロード
記事の運用の方を変える方法です。
Notion に画像を直接アップロードするのではなく、外部のストレージに画像をアップロードして、そのリンクを記事に貼り付けます。
記事の作成に一手間掛かりますが、画像の表示は高速なので、一手間をあまり苦労に感じないのなら最良な手段だと思います。
自分は面倒だったので、採用しませんでした💦
ビルド時、画像を別の無期限のストレージにコピーして、URL を差し替える
ビルド時に画像を無期限のストレージにアップロードし直して、記事中のリンクを差し替える方法です。
API でアクセスできる無期限のストレージを既に持ち合わせているなら、とても有効な手段です。
Vercel では、AWS の S3 と GCP のストレージをオススメしているようです。
ビルド時、画像を Public フォルダにコピーして、URL をローカルのパスに差し替える
自分が最初に試してみた方法です。結果は、上手くいきませんでした💦
理由は、Vercel のデプロイ環境上では自由にファイルやフォルダを編集する権限が与えられていないためです。Vercel にホスティングする際、ビルドエラーが出ます。
考えてみれば、当たり前ですよね。使用者が勝手にファイルを追加したり、削除したりすることが出来ないようになっているのは・・・
この方法を取る場合は、AWS の EC2 など、ハードウェア資源を好きに操作できる IaaS 環境が必要です。Vercel などの PaaS では基本的に上手くいかない筈なので、自分のホスティング環境の事情次第となります。
SWR を利用して、ユーザーがページを開いたとき、クライアントサイドで画像の取得処理を行う
最終的に自分が取った手法は、画像に関しては単純に CSR で都度、画像を取得するというものでした。
ただし、ページをレンダリングする瞬間に useEffect 内で画像を単純にフェッチするのではなく、 Vercel が開発した useSWR というキャッシュ解決のパッケージを使用します。
対象の URL の有効期限を現在時刻と比較して、過ぎていたらフェッチするという処理が書けるので、単純なフェッチより効率の良い処理が行えます。
自分は、この方法を採用することにしました。
おわりに
今回、Notion にアップロードした画像の有効期限切れに対応した訳ですが、想像以上に時間が掛かりました💦
なので、今回のことは未来の自分の備忘録として残しておきます。それでは!