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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。