Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What is going on with this article?
@miyanaga

nginxにおけるWebP画像の選択的レスポンスの設定方法

More than 1 year has passed since last update.

以前、Apache(.htaccessファイル)について書きました。

.htaccessによるWebPの選択的レスポンスとその問題点と改善案

今回はnginxについてです。

拡張子追加の場合(image.jpg→image.jpg.webp)

以前の記事で、.webpという拡張子は元の拡張子を置換するのではなく置き換える方がよいと思うと書きました。

  • path/to/image.jpg → path/to/image.webp ← こちらの置換方式より
  • path/to/image.jpg → path/to/image.jpg.webp ← こちらの追加方式の方がいい

nginxでは、追加方式の場合驚くほど簡単にWebP画像の出し分けを記述することができます。

こちらを参考にしました。

Recipe: serve WebP with nginx conditionally

# serverディレクティブの外で
# Acceptリクエストヘッダにimage/webpが含まれていたら$webp_suffix変数に".webp"を代入
# 含まれていない場合、$webp_suffixは""(空文字列)
map $http_accept $webp_suffix {
    default   "";
    "~*image/webp"  ".webp";
}

server {
# …中略

        # 大文字小文字問わず.pngか.jpgで終わるリクエストについて
        location ~* \.(png|jpe?g)$ {
            # VaryヘッダとしてAcceptを返す
            add_header Vary Accept;
            # WebP対応ブラウザでは、image.jpg.web、image.jpgを探索
            # 非対応のブラウザでは、image.jpg、image.jpgを探索
            # いずれもない場合は404を返す
            try_files $uri$webp_suffix $uri =404;
        }
}

mapディレクティブはプログラミング言語でいうCASE~WHENのような働きをします。
server内部に記述すると設定エラーになりました。

try_filesは、先頭からファイルを探索して最初にヒットしたファイルを返すというものです。

Acceptリクエストヘッダがあるときに、末尾に.webpが付いたファイルを探索するというロジックがスマートに記述されています。

なお、自分はDocker版nginxでテストしたのですが、デフォルトの設定では、以下のようにrootlocation /に記述されていたので、

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

次のようにネストして記述しました。

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        location ~* \.(png|jpe?g)$ {
            add_header Vary Accept;
            try_files $uri$webp_suffix $uri =404;
        }
    }

拡張子置換の場合(image.jpg→image.webp)

こちらは合理的な方法を発見できませんでした。
Luaを使うなどトリッキーな方法しかなさそうです。

こちらが近いかなーと思いましたが、

WordPressでwebpを使って画像サイズ削減

拡張子が置換されたファイルの有無を確認する(そのパス文字列を構成する)というロジックが実現できませんでした。

こちらの記事で見つけました。

次のような設定で拡張子の置換ができるようですが、拡張子追加の記述の方がわかりやすいです。

location ~ ^(/path/to/your/images.+)\.(jpe?g|png)$ {
    if ( $http_accept ~* webp ) {
        set $webp "A";
    }
    if ( $request_filename ~ (.+)\.(png|jpe?g)$ ) {
        set $file_without_ext $1;
    }
    if ( -f $file_without_ext.webp ) {
        set $webp "${webp}E";
    }

    if ( $webp = AE ) {
        add_header Vary Accept;
        rewrite ^(.+)\.(png|jpe?g)$ $1.webp break;
    }
}

nginxではifを使った時点で黄色信号っぽいですね。公式自らこんなエントリーを上げるとは…If Is Evil

この理由もあって、.jpgなどの拡張子を.webpに置き換えるのではなく、拡張子にさらに.webpを追加する方法がオススメなのでした。

9
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
9
Help us understand the problem. What is going on with this article?