我有一些 jpg/png 文件,它们在一个位置(使用image_filter
模块)被调整大小,并且运行良好。但是,我还有webp
一些图像的版本,如果存在,我想提供该webp
版本。如果不存在,jpg/png
则应提供原始图像。
我使用以下配置:
map $http_accept $webp_suffix {
default "";
"~image/webp" "webp";
}
location ~ "/@s/(.*)(png|jpe?g)" {
alias $BASE_PATH/$1;
try_files $webp_suffix $2 $uri;
image_filter resize 1200 -;
image_filter_jpeg_quality 80;
image_filter_buffer 10M;
}
但是415 Unsupported Media Type
当找到 webp 版本时,nginx 会返回错误。如果文件webp
缺失,它会提供 jpg/png 文件而不会出现任何错误。Nginx 版本是1.16.1。
答案1
更简化的配置是:
map $http_accept $webpuri {
~image/webp $uri.webp;
default "";
}
location ~ \.png|jpe?g$ {
try_files $webpuri $uri;
...
}
您的root
指令在此用于获取文件系统上文件的完整路径。
答案2
这不是答案,但太长而无法作为评论。
@TeroKilkanen做出了假设:
它可能
image_filter
从变量读取文件名$uri
,并且认为图像是 JPEG。
让我们看看这是否属实。幸运的是,nginx 是一个开源软件,源代码是ngx_http_image_filter_module
可用的这里。
主要ngx_http_image_body_filter
功能开始在第 291 行。让我们看看开头:
...
switch (ctx->phase) {
case NGX_HTTP_IMAGE_START:
ctx->type = ngx_http_image_test(r, in);
conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
if (ctx->type == NGX_HTTP_IMAGE_NONE) {
if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
out.buf = ngx_http_image_json(r, NULL);
if (out.buf) {
out.next = NULL;
ctx->phase = NGX_HTTP_IMAGE_DONE;
return ngx_http_image_send(r, ctx, &out);
}
}
return ngx_http_filter_finalize_request(r,
&ngx_http_image_filter_module,
NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
}
...
我们看到它是ngx_http_image_test
负责决定图像有效性的函数。让我们看看这个函数(开始在第423行):
static ngx_uint_t
ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in)
{
u_char *p;
p = in->buf->pos;
if (in->buf->last - p < 16) {
return NGX_HTTP_IMAGE_NONE;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"image filter: \"%c%c\"", p[0], p[1]);
if (p[0] == 0xff && p[1] == 0xd8) {
/* JPEG */
return NGX_HTTP_IMAGE_JPEG;
} else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8'
&& p[5] == 'a')
{
if (p[4] == '9' || p[4] == '7') {
/* GIF */
return NGX_HTTP_IMAGE_GIF;
}
} else if (p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G'
&& p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a)
{
/* PNG */
return NGX_HTTP_IMAGE_PNG;
} else if (p[0] == 'R' && p[1] == 'I' && p[2] == 'F' && p[3] == 'F'
&& p[8] == 'W' && p[9] == 'E' && p[10] == 'B' && p[11] == 'P')
{
/* WebP */
return NGX_HTTP_IMAGE_WEBP;
}
return NGX_HTTP_IMAGE_NONE;
}
我认为上面的函数分析缓冲区的前 16 个字节并尝试找到四个已知签名之一,这一点非常清楚。因此问题与变量值无关$uri
。
可能是什么原因?嗯,ngx_http_image_filter_module
文档说下列:
该模块利用库库。建议使用该库的最新版本。
WebP 格式支持出现在 1.11.6 版本中。要转换这种格式的图像,
libgd
库必须在编译时包含 WebP 支持。
也许问题出在你的 nginx 构建中。检查 WebP 和image_filter
兼容性,无需任何额外的 URI 转换,例如
location ~ \.webp$ {
image_filter resize 1200 -;
image_filter_jpeg_quality 80;
image_filter_buffer 10M;
}
然后明确请求现有的 WebP 文件。如果仍然出现错误415 Unsupported Media Type
,则问题很可能出在您的 nginx 构建中。