CloudFrontにおけるWebPの選択的レスポンス
CloudFrontにおけるWebPの選択的レスポンス:
WebPファイルがある場合、対応ブラウザにはそれを返すWebサーバーの設定方法について書いてきました。
S3に画像ファイルを配置するケースも増えていますが、S3自体には上記の代替となるようなURL書き換えの仕組みがありません。
そこでCloudFrontにリクエストやレスポンスを変換するロジックを実装できる、Lambda@Edgeを使う方法を試してみました。
実際にCloudFront経由でJpegとWebPを選択配信している画像がこちらです。
https://d2b6zhehadjtvu.cloudfront.net/extappend/png/png-and-webp.png
同じURLですが、ChromeだとWebPロゴ、Firefoxだとサイコロが表示されます。
https://d2b6zhehadjtvu.cloudfront.net/extappend/png/only-png.png
対応するWebP画像がないので、ChromeでもFirefoxでもサイコロが表示されます。
このようなJavaScriptコードを書きました。
S3に限らず汎用的なWebサーバをオリジンにできます。
実際に設定するには、CloudFrontの対象
Lambda@Edgeは、通常のLambda関数と異なる点がいくつかあるようです。
Lambda 関数の要件と制限
設定について詳しい手順もまた今度、書いてみたいと思います。
WebPファイルがある場合、対応ブラウザにはそれを返すWebサーバーの設定方法について書いてきました。
S3に画像ファイルを配置するケースも増えていますが、S3自体には上記の代替となるようなURL書き換えの仕組みがありません。
そこでCloudFrontにリクエストやレスポンスを変換するロジックを実装できる、Lambda@Edgeを使う方法を試してみました。
デモ
実際にCloudFront経由でJpegとWebPを選択配信している画像がこちらです。https://d2b6zhehadjtvu.cloudfront.net/extappend/png/png-and-webp.png
同じURLですが、ChromeだとWebPロゴ、Firefoxだとサイコロが表示されます。
https://d2b6zhehadjtvu.cloudfront.net/extappend/png/only-png.png
対応するWebP画像がないので、ChromeでもFirefoxでもサイコロが表示されます。
Lambda@Edge用JavaScriptコード
このようなJavaScriptコードを書きました。Accept
ヘッダは簡単に取得できます。WebP画像(image.png.webp)の有無は実際にオリジンに対してHEAD
リクエストを送信して確認します。S3に限らず汎用的なWebサーバをオリジンにできます。
実際に設定するには、CloudFrontの対象
Behavior
でLambda Function Associations
にOrigin Request
として対してこのLambda関数を割り当てます。Include Body
は不要です。Whitelist Headers
にAccept
を追加することも必要なはずです。const BASE_URL = 'https://s3.amazonaws.com/webp-lambda-edge-test'; const TIMEOUT = 3 * 1000; const https = require('https'), url = require('url'); exports.handler = async (event, context) => { const request = event.Records[0].cf.request; // JpegまたはPNGファイルへのリクエストのみ対応 if (request.uri.match(/\.(jpe?g|png)$/)) { // Acceptヘッダがimage/webpを含むか let webpAcceptable = false; try { if (request.headers.accept[0].value.match(/image\/webp/i)) webpAcceptable = true; } catch (ex) {} if (webpAcceptable) { // WebP対応ブラウザの場合はWebP版ファイルの有無をHEADメソッドで確認 await new Promise((resolve, reject) => { const webpUri = request.uri + '.webp'; const req = url.parse(BASE_URL + webpUri); req.method = 'HEAD'; req.timeout = TIMEOUT; https.request(req, res => { // ステータスコード2XXであればWebPが存在するのでリクエストURIを変更 if (res.statusCode >= 200 && res.statusCode < 300) request.uri = webpUri; resolve(); }).on('error', reject).end(); }); } } return request; };
Lambda 関数の要件と制限
設定について詳しい手順もまた今度、書いてみたいと思います。
コメント
コメントを投稿