Задать вопрос
monochromer
@monochromer
DIVeloper

Почему в Nginx не работают переменные для try_files?

Пытаюсь решить такую задачу - вместо картинок png и jpeg раздавать заранее созданные варианты для avif и webp, если браузер их поддерживает. Например, браузер запрашивает картинку `image.png`. Если поддерживает и avif и webp, то пробуем сначала отдать картинку `image.png.avif`, если её нет, то картинку `image.png.webp`. Если и её нет, то отдаём саму картинку `image.png`.

Основаная логика такая:

location ~* \.(png|jpe?g|gif)$  {
  set $avif_image_path "";
  if ($http_accept ~* "image/avif") {
    set $avif_image_path "$uri.avif";
  }

  set $webp_image_path "";
  if ($http_accept ~* "image/webp") {
    set $webp_image_path "$uri.webp";
  }

  add_header Vary Accept;

  try_files $avif_image_path $webp_image_path $uri =404;
}


Но Nginx всегда возвращает оригинальный файл изображения.

Полный листинг конфига:
spoiler

worker_processes auto;

events {
  worker_connections 1024;
  multi_accept on;
}

http {
  access_log /dev/stdout;
  error_log /dev/stdout info;

  charset utf-8;
  server_tokens off;
  sendfile on;
  tcp_nodelay on;
  tcp_nopush on;

  include mime.types;
  default_type application/octet-stream;

  server {
    listen 80;

    root /usr/share/nginx/public;
    index index.html index.xml;

    location ~* \.(png|jpe?g|gif)$  {
      set $avif_image_path "";
      if ($http_accept ~* "image/avif") {
        set $avif_image_path "$uri.avif";
      }

      set $webp_image_path "";
      if ($http_accept ~* "image/webp") {
        set $webp_image_path "$uri.webp";
      }

      add_header Vary Accept;
      add_header X-Debug "avif: `$avif_image_path`, webp: `$webp_image_path`, uri: `$uri`";

      try_files $avif_image_path $webp_image_path $uri =404;
    }
  }
}


Репозиторий с примером - https://github.com/monochromer/nginx-image-test
  • Вопрос задан
  • 143 просмотра
Подписаться 1 Средний 5 комментариев
Решения вопроса 2
@dodo512
Когда истинно уловие if исполняется только содержимое блока if.
И то что унаследовано от основной конфигурации, например, add_header.
А вот try_files не наследуется и исполняется только когда уловие if ложно.

Эти проблемы возникают только в контексте location.
При использовании if в контексте server таких проблем нет.
Достаточно перенести if на уровень server и всё заработает как ожидалось.
server {
  set $avif_image_path "";
  if ($http_accept ~* "image/avif") {
    set $avif_image_path "$uri.avif";
  }

  set $webp_image_path "";
  if ($http_accept ~* "image/webp") {
    set $webp_image_path "$uri.webp";
  }

  location ~* \.(png|jpe?g|gif)$  {
    add_header Vary Accept;

    try_files $avif_image_path $webp_image_path $uri =404;
  }


Или как советовали в комментариях избавиться от if и переписать на map.
Ответ написан
Lynn
@Lynn
nginx, js, css
Вариант с map:

map $http_accept $avif_image_path {
  default "";
  ~image/avif "$uri.avif";
}
map $http_accept $webp_image_path {
  default "";
  ~image/webp "$uri.webp";
}

server {
  # ...
  location ~* \.(png|jpe?g|gif)$  {
    add_header Vary Accept;

    try_files $avif_image_path $webp_image_path $uri =404;
  }
  # ...
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы