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だとサイコロが表示されます。
68747470733a2f2f643262367a68656861646a74

https://d2b6zhehadjtvu.cloudfront.net/extappend/png/only-png.png

対応するWebP画像がないので、ChromeでもFirefoxでもサイコロが表示されます。


68747470733a2f2f643262367a68656861646a74



Lambda@Edge用JavaScriptコード

このようなJavaScriptコードを書きました。

Acceptヘッダは簡単に取得できます。WebP画像(image.png.webp)の有無は実際にオリジンに対してHEADリクエストを送信して確認します。

S3に限らず汎用的なWebサーバをオリジンにできます。

実際に設定するには、CloudFrontの対象BehaviorLambda Function AssociationsOrigin Requestとして対してこのLambda関数を割り当てます。Include Bodyは不要です。

Whitelist HeadersAcceptを追加することも必要なはずです。

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@Edgeは、通常のLambda関数と異なる点がいくつかあるようです。

Lambda 関数の要件と制限

設定について詳しい手順もまた今度、書いてみたいと思います。

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)