Рейтинг:0

Nginx возвращает 415 при использовании image_filter с webp

флаг za

У меня есть несколько файлов jpg/png, размер которых изменяется в определенном месте (с image_filter модуль) и он работает нормально.Но у меня также есть сеть версии некоторых изображений, и я хочу служить сеть один, если он существует. Если нет то оригинал jpg/png изображение должно быть подано.

Я использую следующую конфигурацию:

карта $http_accept $webp_suffix {
    По умолчанию        "";
    "~изображение/webp" "webp";
}

расположение ~ "/@s/(.*)(png|jpe?g)" {
    псевдоним $BASE_PATH/$1;
    try_files $webp_suffix $2 $uri;

    image_filter изменить размер 1200 -;
    image_filter_jpeg_quality 80;
    image_filter_buffer 10M;
}

Но nginx возвращает 415 Неподдерживаемый тип носителя ошибка при обнаружении версии webp. Если сеть файл отсутствует, он обслуживает файл jpg/png без каких-либо ошибок. Версия Nginx 1.16.1.

Ivan Shatsky avatar
флаг gr
Отвечает ли это на ваш вопрос? [NGINX: map и try\_files не работают](https://serverfault.com/questions/1036804/nginx-map-and-try-files-not-working)
Ivan Shatsky avatar
флаг gr
Помимо того, что вы неправильно используете директиву `try_files`, есть еще одно предостережение, связанное с использованием производных переменных `map` внутри местоположения регулярного выражения с пронумерованными группами захвата. Объяснение и рабочий пример приведены здесь: [NGINX: map и try_files не работают](https://serverfault.com/questions/1036804/nginx-map-and-try-files-not-working).
Erfun avatar
флаг za
@IvanShatsky Я изменил числовые переменные на именованные переменные, но не вижу разницы. Все еще получаю «415 Unsupported Media Type».
флаг us
Возможно, image_filter считывает имя файла из переменной $uri и думает, что это изображение в формате JPEG.
Erfun avatar
флаг za
@TeroKilkanen Как описано в документации, WEBP должен поддерживаться в image_filter, но по какой-то причине он не работает.
флаг us
Я предполагаю, что он правильно поддерживает формат WEBP, когда фактический URL-адрес запроса содержит расширение `.webp`. В вашей конфигурации URL-адрес запроса имеет формат `.png` или `.jpg`, в зависимости от исходного расширения. Поэтому `image_filter` пытается получить доступ к изображению, используя неправильный декодер. Может оказаться невозможным объединить модули отображения и `image_filter`.
drboczek avatar
флаг dk
Вы решили свою проблему с nginx и webp? У меня та же проблема :) Centos 7 тоже, epel nginx 1.20 Я пытаюсь использовать репозиторий nginx с nginx 1.21, но безрезультатно.
Erfun avatar
флаг za
@drboczek К сожалению, нет, не смог. Вместо этого я использовал функцию преобразования WEBP нашего поставщика CDN, которая также доступна на Cloudflare.
Рейтинг:0
флаг us

Более упрощенная конфигурация для этого:

карта $http_accept $webpuri {
    ~изображение/webp $uri.webp;
    По умолчанию        "";
}

расположение ~ \.png|jpe?g$ {
    try_files $webpuri $uri;
    ...
}

Твой корень Здесь используется директива для получения полного пути к файлам в вашей файловой системе.

Erfun avatar
флаг za
Я не понимаю, где разница. Я использовал псевдоним вместо root для указания пути к файлу в файловой системе.
флаг us
Приведенный выше код не использует регулярные выражения для разделения URI на базовую часть имени файла и расширение, что довольно хакерски. Вместо этого мы берем полный путь к файлу и добавляем `.webp` после всего пути.
Erfun avatar
флаг za
Я думаю, проблема вызвана `image_filter`, а не регулярным выражением. Если я удалю image_filter, мой собственный код будет работать. Так что, очевидно, нет ничего плохого в обращении к файлу.
Рейтинг:0
флаг gr

Не ответ, но слишком длинный, чтобы быть комментарием.

@ТероКилканен сделал предположение:

Может быть, это image_filter читает имя файла из $ури переменная, и он думает, что изображение в формате JPEG.

Давайте проверим, правда ли это. К счастью, nginx — это программное обеспечение с открытым исходным кодом, и исходный код ngx_http_image_filter_module доступен здесь.

Главный ngx_http_image_body_filter функция начал в строке 291.Смотрим начало:

    ...
    переключатель (ctx->фаза) {

    случай 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);

        если (ctx-> тип == NGX_HTTP_IMAGE_NONE) {

            если (conf->фильтр == NGX_HTTP_IMAGE_SIZE) {
                out.buf = ngx_http_image_json(r, NULL);

                если (out.buf) {
                    выход.следующий = NULL;
                    ctx->фаза = NGX_HTTP_IMAGE_DONE;

                    вернуть ngx_http_image_send (r, ctx, & out);
                }
            }

            вернуть ngx_http_filter_finalize_request(r,
                                              &ngx_http_image_filter_module,
                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
        }
        ...

Мы видим, что это ngx_http_image_test функция, которая отвечает за решение о достоверности изображения. Давайте посмотрим на эту функцию (начал в строке 423):

статический 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) {
        вернуть NGX_HTTP_IMAGE_NONE;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->соединение->журнал, 0,
                   "фильтр изображения: \"%c%c\"", p[0], p[1]);

    если (p[0] == 0xff && p[1] == 0xd8) {

        /* JPEG */

        вернуть NGX_HTTP_IMAGE_JPEG;

    } else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8'
               && р[5] == 'а')
    {
        если (p[4] == '9' || p[4] == '7') {
            /* GIF */
            вернуть 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 */

        вернуть 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 */

        вернуть NGX_HTTP_IMAGE_WEBP;
    }

    вернуть NGX_HTTP_IMAGE_NONE;
}

Я думаю, довольно ясно, что приведенная выше функция анализирует первые 16 байтов буфера, пытаясь найти одну из четырех известных сигнатур. Так что проблема не в нем $ури переменное значение.

Что может быть причиной? Хорошо, ngx_http_image_filter_module документация говорит последующий:

Этот модуль использует libgd библиотека. Рекомендуется использовать последнюю доступную версию библиотеки.

Поддержка формата WebP появилась в версии 1.11.6. Для преобразования изображений в этот формат libgd библиотека должна быть скомпилирована с поддержкой WebP.

Возможно, проблема в вашей сборке nginx. Проверьте WebP и image_filter совместимость без каких-либо дополнительных преобразований URI, что-то вроде

расположение ~ \.webp$ {
    image_filter изменить размер 1200 -;
    image_filter_jpeg_quality 80;
    image_filter_buffer 10M;
}

а затем явно запросить существующий файл WebP. Если вы все еще получите 415 Неподдерживаемый тип носителя ошибка, проблема, скорее всего, в вашей сборке nginx.

Erfun avatar
флаг za
Я протестировал `image_filter` с `webp`, и возникла та же проблема `415 Unsupported Media Type`. Так что скорее всего проблема с `libgd`. Я установил свой nginx из официального репозитория yum. Должен ли я создавать его вручную с любой пользовательской конфигурацией?
Ivan Shatsky avatar
флаг gr
Какой дистрибутив Linux вы используете?
Erfun avatar
флаг za
Это сервер Centos 7.
Ivan Shatsky avatar
флаг gr
И еще один вопрос, какой репозиторий вы используете? Это официальный репозиторий nginx или EPEL или что-то еще?
Erfun avatar
флаг za
Это репозиторий EPEL.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.