前情提要详见文章《Nginx尝试返回webp版本的图片给浏览器》。
在文章中,我提到了多个location是为了rewrite会转义导致非英文名文件,字符转义后,实际找不到硬盘文件(硬盘文件存储是未转义前的名字),所以使用了多个location的方式来解决。
虽然多个location实际对nginx来说也没什么太多的性能影响,但里面还有rewrite,我一直对rewrite的性能有偏见,但是用正常逻辑做出来的不需要rewrite的正则,nginx总不能正常匹配。
后面查阅文章后,发现是Nginx的变量覆盖问题(惰性求值与全局正则覆盖),导致正则匹配后的结果(如$1、$2这种),会因为其他变量被覆盖或执行前匹配了。
而这个问题,可以通过正则的命名捕获组来解决,那最终我们可以不使用rewrite且一个location来解决我们这个需求,加上对非必要的匹配使用了非捕获组,更加节省性能(对比之前文章的方法也算是质的飞跃了)。
目前解决后,我们的实现方法如下,在nginx.conf的http块中定义:
map $http_accept $webp_prefix {
default "";
"~*webp" "webp/";
}
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
在你的vhost中,使用:
location ~* ^/wp-content/(?<folder>thumbnails|uploads)/(?<img_path>.+\.(?:png|jpg|jpeg))$ {
more_set_headers "Vary: Accept";
more_set_headers "Cache-Control: public, no-transform, max-age=2592000";
try_files /wp-content/$webp_prefix$folder/$img_path$webp_suffix $uri =404;
}
这样便可以实现请求wp-content目录下的thumbnails和uploads目录,在浏览器支持的情况下,尝试去wp-content/webp目录下的thumbnails和uploads目录寻找webp文件并返回;如果不存在对应webp文件,会在原始位置调用源文件返回(由$uri保障)。在浏览器不支持的情况下,第一个实际匹配的就是原始位置,即便有意外,也有$uri兜底。如果都不存在,调用404。
另外可以通过以下配置对webp文件,进行缓存过期设置:
location ~* ^/wp-content/webp/.*\.webp$ {
more_set_headers "Vary: Accept";
more_set_headers "Cache-Control: public, no-transform, max-age=2592000";
}
其他注意和建议事项,见之前文章《Nginx尝试返回webp版本的图片给浏览器》,不再赘述。
这篇文章也算是个记录,提醒自己只要在正则相关配置中引入了map、rewrite等可能涉及变量覆写的,就应当抛弃$1和$2这种传统方式,改用(?<name>...)命名捕获组来实现需求。
转载请注明转自: kn007的个人博客 的《改进Nginx在支持时返回webp的逻辑》

我已经全转webp了 原图已删除
@龙笑天: 我之前也是这样,但后面还是找回备份,使用现在方法。因为也不一定webp就小,我现在策略是webp小就加载webp(其实应该按百分比算会更正确一些,但是懒得多余判断了),webp一般来说加载并不如png和jpg,图片多且大的时候就很明显了。