nginx 中需用 map 指令提取 $http_accept 判断 webp 支持,再通过 try_files $uri$webp_suffix $uri =404 实现自动回退;必须配置 mime 类型、vary: accept 头及预生成 .webp 文件。

在 Nginx 中,不能用 rewrite 直接“验证”WebP 支持,因为 rewrite 本身不解析 Accept 头或做条件判断——它只做 URI 字符串匹配与替换。真正判断客户端是否支持 WebP,必须靠 map 指令提取请求头信号,再结合 try_files 或 rewrite + if(不推荐)来实现路径回退或重写。
用 map 提取 WebP 支持状态(必须第一步)
map 是唯一安全、高效、且被官方推荐的方式,用于把 $http_accept 转成可复用的变量:
- 必须写在
http { }块顶层,不能放在server或location内 - 典型写法:
map $http_accept $webp_suffix {
default "";
"~*image/webp" ".webp";
} - 该变量值为
.webp表示浏览器声明支持,为空则不支持
通过 try_files 实现“零开销自动回退”(推荐方式)
这不是 rewrite,但效果更可靠、无性能损耗,且天然适配缓存:
- 在图片 location 中(如
location ~ \.(jpg|png|gif)$)写:
try_files $uri$webp_suffix $uri =404; - Nginx 先检查
/path/photo.jpg.webp是否存在;存在就返回,不存在就 fallback 到/path/photo.jpg - 无需 if、无需 rewrite,避免循环重写和性能陷阱
若坚持用 rewrite + if(不推荐,仅作说明)
虽然可行,但 if 在 location 中有诸多限制和隐式行为,容易出错:
- 示例(仅限测试,生产环境慎用):
if ($http_accept ~* "image/webp") {
set $webp_file "$request_filename.webp";
if (-f $webp_file) {
rewrite ^(.*)$ $1.webp break;
}
} - 问题明显:嵌套 if 不被官方支持;
rewrite ... break会终止后续指令,可能干扰 expires、Vary 等设置 - 且
$request_filename依赖 root/alias 配置,路径易错,调试困难
必须同步配置的配套项
无论用哪种方式,以下三项缺一不可,否则 WebP 无法正确生效:
-
MIME 类型注册:确保
mime.types或 http 块中有image/webp webp;,否则 .webp 文件会被当 text/plain 下载 -
Vary: Accept 头:在图片 location 中加
add_header Vary "Accept";,防止 CDN 或代理缓存错版本 -
WebP 文件已预生成:Nginx 不转图,只选图。需提前用
cwebp批量生成xxx.jpg.webp等同名文件











