Let the website adaptively load the corresponding format of images based on whether the browser supports WebP. If we judge it in the code, the workload will be huge because we need to modify the reference method of each image in the code. Is there a simpler and more efficient method? The answer is yes, and that is to modify the configuration of Nginx.
Main Idea#
How to determine whether the browser supports WebP format images? In addition to loading a 1x1 pixel WebP image in the front end to obtain the width, there is another method, which is to check the Accept field in the request header sent by the browser. If this field contains image/webp
, it means that the browser supports WebP; otherwise, it does not support.
Request header Accept field of IE that does not support WebP:
Request header Accept field of Firefox that supports WebP:
Request header Accept field of Chrome that supports WebP:
Based on this, we can modify the Nginx configuration file to judge the requests with .jgp
, .jpeg
, and .png
extensions and the request header Accept field containing image/webp
. We write this judgment in a Lua file. In the Lua file, we first check if the corresponding WebP file exists. If it exists, we directly redirect to the WebP file. If it does not exist, we call the libwebp method to generate the WebP file and then redirect.
With this idea, let's give it a try.
Preparation for Modification#
Install Lua module for Nginx#
Omitted
Install libwebp on the server#
Reference: Nginx+Lua+libwebp for Automatic Server Image Conversion to WebP
Nginx.conf
#
Because if
cannot judge multiple conditions at the same time, we define a variable and modify its value with if
. Finally, we judge whether all conditions are met based on the value of this variable.
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
#
The main task of this file is to first check if the corresponding WebP file exists. If it exists, we directly redirect to the WebP file. If it does not exist, we call the libwebp method to generate the WebP file and then redirect.
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
Testing#
When we open the same image address with IE that does not support WebP and Chrome that supports WebP, we find that the response content returned by the server is different.
The response content for Chrome that supports WebP is an image in WebP format:
The response content for IE that does not support WebP is a regular jpg image: