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

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。