Contentfulから効率的に画像配信しよう!

ヘッドレスCMSのContentfulは画像配信に特化した API が存在し、かんたんに画像配信を最適化できます。
2021.02.18

ContentfulはヘッドレスCMSサービスです。 JAMstack の API コンポーネントとして、CMS コンテンツを管理します。

今回は、コンテンツに付随する画像の配信部分を調べる機会がありましたので、紹介します。

Contentful の画像配信の特徴

Contentful の画像配信は以下の特徴を持っています。

  • CDN(Amazon CloudFront) から配信
  • 画像CDNサービスと同じくURLで画像を操作
  • 画像形式の変換(JPEGからWebP)、画質調整、サイズ調整など、シンプルな画像加工が可能

順に解説します。

CDN(Amazon CloudFront)から配信

Contentful で管理される画像アセットは、画像CDNとして専用ドメイン(images.ctfassets.net)から配信されます。

したがって、デフォルトの状態で画像はエッジでキャッシュされ、高速・効率的にクライアントに配信されます。

この画像配信 CDN として Amazon CloudFront が使われています。

$ dig +noall +ans images.ctfassets.net.
images.ctfassets.net.	3552	IN	CNAME	ctfassets-images.contentful.net.
ctfassets-images.contentful.net. 1152 IN CNAME	d3orhvfyxudxxq.cloudfront.net.
d3orhvfyxudxxq.cloudfront.net. 12 IN	A	99.84.158.98
d3orhvfyxudxxq.cloudfront.net. 12 IN	A	99.84.158.51
d3orhvfyxudxxq.cloudfront.net. 12 IN	A	99.84.158.18
d3orhvfyxudxxq.cloudfront.net. 12 IN	A	99.84.158.91

オリジン画像がこのCDNから配信されているだけでなく、画像APIもこのドメイン配下で構築されています。

なお、 REST/GraphQL API は CDN に fastly を使っています。

$ dig +noall +ans graphql.contentful.com.
graphql.contentful.com.	3600	IN	CNAME	n2.shared.global.fastly.net.
n2.shared.global.fastly.net. 30	IN	A	151.101.2.49
n2.shared.global.fastly.net. 30	IN	A	151.101.66.49
n2.shared.global.fastly.net. 30	IN	A	151.101.130.49
n2.shared.global.fastly.net. 30	IN	A	151.101.194.49

画像CDNサービスと同じくURLで画像を操作

Contentful の Images API は GET ベースで画像を要求し、クエリーストリングで画像を加工します。

Image API を利用することで、より効果的な画像配信が可能です。

オリジナル画像を要求

オリジナル画像を要求する場合は、次の通りです。

$ curl --include \
  --request GET \
  https://images.ctfassets.net/{space_id}/{asset_id}/{token}/{name}

HTTP/2 200
content-type: image/jpeg
content-length: 27187
date: Wed, 17 Feb 2021 12:03:41 GMT
last-modified: Mon, 20 Feb 2017 17:18:40 GMT
etag: "ee08e7783ada6c3855b4aef784912c36"
cache-control: max-age=31536000
server: Contentful Images API
access-control-allow-origin: *
x-cache: Miss from cloudfront
via: 1.1 5cf5bc69324ade55eebb5e539fa6c2fa.cloudfront.net (CloudFront)
x-amz-cf-pop: TXL52-C1
x-amz-cf-id: 29n7Hsh2Hvlk3fCRFk50VsP4KVmaQuxNsdD1Eh1nqMpMdnNZ3AWd9g==

...

レスポンスヘッダーから、Contentful Images API で処理されていたり、CDN に CloudFront を使っていることがわかりますね。

画像形式を WebP に変換してファイルサイズ削減

WebP はGoogleが開発した新世代の効率的な画像であり、最新の主要ブラウザはサポートしています。

先程の画像を JPEGを WebP に変換したい場合、クエリーストリング fm=webp を追加します。

$ curl --include \
  --request GET \
  https://images.ctfassets.net/{space_id}/{asset_id}/{token}/{name}?fm=webp

HTTP/2 200
content-type: image/webp
content-length: 5420
...

Content-Typeimage/webp に変わり、画像のサイズ(content-length)が 27187 バイトから 5420 バイトへとわずか 20% になりました。

WebP のブラウザ対応状況はブラウザとそのバージョンにより異なります。

Contentful の Image APIはクライアントの User-Agent を元に自動的に最適な画像形式に変換することはできません。実運用では何らかの判定ロジックを挟んだり、source setsで PNG/JPEG にフォールバックさせる必要があります。

画質を調整してファイルサイズ削減

画像ファイルサイズを汎用的に最適化したい場合、画質の調整がおすすめです。 画質の調整には q パラメーターを用い、1(最低)〜100(最高)の範囲で指定します。

先程のJPEGオリジナル画像に対して q=50 を指定すると、ファイルサイズは 27187 バイトから 8939 バイトへと 32.9% になりました。

WebP変換と画質変換を同時に行うと(?fm=webp&q=50) 4124 バイトになりました。JPEG の元画像の15%、WebP 変換だけをした時に比べ 76% になりました。

OGP 画像を生成

Image API を利用すると、SNS 共有時に利用される OGP 画像もかんたんに作成できます。

1200 x 630 の JPEG 画像を作成し、余ったエリアを背景色で埋める場合、?fm=jpeg&w=1200&h=630&fit=pad&bg=rgb:ffffffといったクエリーストリングを渡します。

$ curl --include \
  --request GET \
  https://images.ctfassets.net/{space_id}/{asset_id}/{token}/{name}?fm=jpeg&w=1200&h=630&fit=pad&bg=rgb:ffffff

現時点では、動的に記事タイトルのような文字列を含んだ画像を生成することはできません。

画像処理時間

画像加工に伴うサーバーの処理時間を求めます。

cURL のリクエスト時に各処理ごとの時間を出力するように設定し、 time_starttransfer - time_appconnect を求めると、TTFB(Time To First Byte) と同等の時間を求まることができます。

Contentful の Getting Started でサンプルブログを作成すると、初期画像が投入されます。 これら画像から3枚を選び、キャッシュがない状態で画像変換をする・しない場合の処理時間を比較したところ、画像変換のために処理時間が 約0.4秒 程度伸びました

  • オリジナル画像の要求 → 0.6〜0.7秒
  • オリジナル画像に対して OGP 向けの画像加工(?w=1200&h=630&fit=pad&bg=rgb:ffffff) → 1〜1.2秒

導入検討時には、より多くの画像で計測ください。

計測実行結果

$ cat ~/.curlrc
-w "dnslookup: %{time_namelookup} | connect: %{time_connect} | appconnect: %{time_appconnect} | pretransfer: %{time_pretransfer} | starttransfer: %{time_starttransfer} | total: %{time_total} | size: %{size_download}\n"

# 画像加工無し
$ curl -so /dev/null https://images.ctfassets.net/{space_id}/{asset_id}/{token}/matt-palmer-254999.jpg
dnslookup: 0.061954 | connect: 0.111547 | appconnect: 0.226365 | pretransfer: 0.226468 | starttransfer: 0.843249 | total: 1.550428 | size: 2293094

# 画像加工有り
$ curl -so /dev/null https://images.ctfassets.net/{space_id}/{asset_id}/{token}/matt-palmer-254999.jpg\?w=1200\&h=630\&fit=pad\&bg=rgb:ffffff
dnslookup: 0.051683 | connect: 0.095307 | appconnect: 0.202715 | pretransfer: 0.202992 | starttransfer: 1.232042 | total: 1.298567 | size: 85457

削除処理について

一度公開した画像を削除したいことがあります。

削除APIを実行後、CDN キャッシュの削除を含め、削除処理が完了するまで最大で48時間かかります。

即時パージには対応していないので、ご注意ください。

Deleting an asset will remove the current asset and all previously referenced files on the CDN. It can take up to 48 hours until these files will be made unavailable from (assets|images|downloads|videos).ctfassets.net.

https://www.contentful.com/developers/docs/references/content-management-api/#/reference/assets/published-assets-collection

最後に

ヘッドレスCMSのContentfulは画像配信に特化した API が存在し、画質の調整、サイズ変更、画像形式の変換といった画像最適化をオプション契約無しに利用できます。

より高機能な画像処理が必要な場合は、画像CDN の Cloudinary と連携することも可能です。

クラスメソッドはContentfulとCloudinaryのパートナーとして導入のお手伝いをさせていただいています。

お気軽にお問い合わせください。

それでは。

参考