banner
半米牙

半米牙的笔记

分享技术、记录生活
email

浏览器 WebP 画像の自動適応読み込み

ウェブサイトは、ブラウザが WebP をサポートしているかどうかに基づいて、対応する形式の画像を自動的に読み込むようにすることができます。コードで判断すると、非常に手間がかかるため、すべての画像の参照方法を変更する必要があります。簡単で効率的な方法はありますか?答えはあります。それは Nginx の設定を変更することです。

主なアイデア#

WebP 形式の画像をブラウザがサポートしているかどうかを判断する方法は、1×1 ピクセルの WebP 画像をフロントエンドで読み込んで幅を取得する方法だけでなく、リクエストヘッダの Accept フィールドを確認する方法もあります。このフィールドにimage/webpが含まれている場合、ブラウザは WebP をサポートしていることを意味し、そうでなければサポートしていません。

WebP をサポートしていない IE のリクエストヘッダの Accept フィールド:

webp1

WebP をサポートしている Firefox のリクエストヘッダの Accept フィールド:

webp2

WebP をサポートしている Chrome のリクエストヘッダの Accept フィールド:

webp4
これに基づいて、Nginx の設定ファイルを変更し、拡張子が **.jgp.jpeg.pngで終わるリクエスト ** かつリクエストヘッダの Accept フィールドにimage/webpが含まれているリクエストに対して WebP ファイルの判断を行います。この判断は Lua ファイルに記述します。Lua ファイルでは、対応する WebP ファイルが存在するかどうかをまず判断し、存在する場合は直接 WebP ファイルにリダイレクトし、存在しない場合は libwebp メソッドを呼び出して WebP ファイルを生成し、その後にリダイレクトします。

このアイデアを試してみましょう。

変更の準備#

Nginx で Lua モジュールをインストールする#

省略

サーバーで libwebp をインストールする#

参考:Nginx+Lua+libwebp 实现服务器图片自动转 WebP

Nginx.conf#

if 文では複数の条件を同時に判断することができないため、変数を定義し、if 文で変数の値を変更し、最後にその変数の値に基づいてすべての条件を満たしているかどうかを判断します。

location /img {
    set  $cwebp_flag 0;

    if ($uri ~ \.(png|jpg|jpeg)$) {
        set  $cwebp_flag '${cwebp_flag}1';
    }

    if ($http_accept ~ image/webp) {
        set  $cwebp_flag '${cwebp_flag}1';
    }

    if ($cwebp_flag = 011) {
        content_by_lua_file  lua/imgProcess.lua;
    }
}

imgProcess.lua#

このファイルの主な役割は、対応する WebP ファイルが存在するかどうかをまず判断し、存在する場合は直接 WebP ファイルにリダイレクトし、存在しない場合は libwebp メソッドを呼び出して WebP ファイルを生成し、その後にリダイレクトすることです。

function file_exists(name)
	local f=io.open(name,"r");
    if f~=nil then io.close(f) return true else return false end
end
 
local originalFile = ngx.var.request_filename;
local newFile = ngx.var.request_filename .. ".webp";

if not file_exists(newFile) then
  if not file_exists(originalFile) then
    ngx.exit(404);
    return;
  end

  os.execute("cwebp -q 75 " .. originalFile  .. " -o " .. newFile); 

  if file_exists(newFile) then
    ngx.header.vary = 'accept, accept-encoding';
    ngx.header.x_webp = 'generate';
    ngx.header.real_source_url = ngx.var.uri .. ".webp";
    ngx.header.content_type = "image/webp";
    return ngx.exec(ngx.var.uri .. ".webp");
  else
    ngx.exit(500);
    return;
  end
else
  ngx.header.vary = 'accept, accept-encoding';
  ngx.header.x_webp = 'read';
  ngx.header.real_source_url = ngx.var.uri .. ".webp";
  ngx.header.content_type = "image/webp";
  return ngx.exec(ngx.var.uri .. ".webp");
end

テスト#

WebP をサポートしていない IE と WebP をサポートしている Chrome で同じ画像のアドレスを開くと、サーバーから返されるレスポンスの内容が異なることがわかります。

WebP をサポートしている Chrome のレスポンスの内容は WebP 形式の画像です:

webp5

一方、WebP をサポートしていない IE のレスポンスの内容は通常の jpg 画像です:

webp6

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。