Nginx 在将 image_filter 与 webp 结合使用时返回 415

Nginx 在将 image_filter 与 webp 结合使用时返回 415

我有一些 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 构建中。

相关内容