xChar
·5 years ago

让网站根据浏览器是否支持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

Loading comments...