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 関数の要件と制限
設定について詳しい手順もまた今度、書いてみたいと思います。
コメント
コメントを投稿