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#
To determine whether the browser supports WebP format images, besides 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 the browser supports WebP; otherwise, it does not.
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 configuration file of Nginx to judge whether the requests ending with .jpg
, .jpeg
, and .png
and with the request header Accept field containing image/webp
should be processed as WebP files. 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 try it.
Preparation for Modification#
Install Lua module for Nginx#
Omitted
Install libwebp on the server#
Refer to: Nginx+Lua+libwebp for Automatic Server Image Conversion to WebP
Nginx.conf
#
Because the if
statement cannot judge multiple conditions at the same time, we define a variable and use if
to modify its value. 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
#
This file mainly works as follows: first, check if the corresponding WebP file exists. If it exists, directly redirect to the WebP file. If it does not exist, check if the original file exists. If it does not exist, return a 404 error. Then, call the libwebp method to generate the WebP file and 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 opening the same image address with a browser that does not support WebP (IE) and a browser that supports WebP (Chrome), we find that the response content returned by the server is different.
The response content for Chrome that supports WebP is a WebP format image:
The response content for IE that does not support WebP is a regular jpg image: