Как в Nginx настроить передачу файла с нестандартным расширением?

Всем привет! 

У меня есть вопрос по реализации одной идеи. На сервере хранятся файлы с расширениями .jpeg и .gif. В случаях, когда запрашивается файл .gif, вместо него выводится .jpeg-заглушка. Однако, когда запрос идет напрямую на оригинальный файл .jpeg, возникает проблема с отсутствием этого файла. 

В конфигурации Nginx у меня прописан следующий блок location: 
<pre><code>location @original {
        try_files $image_folder_1$uri  $image_folder_0$uri @errors;
}</code></pre>

Проблема в том, что когда файл запрашивают с правильным расширением .jpeg, все работает как надо. Но для некоторых файлов есть расширение .gif, и если происходит запрос на file.jpeg, то этого файла нет, хотя существует file.gif. 

Я хочу добавить в этот блок location дополнительную проверку на наличие файла .gif на основании запроса к .jpeg. Если файл .gif существует, нужно сделать редирект 301 с file.jpeg на file.gif. Если же .gif отсутствует, перенаправить на @errors. 

Либо, в крайнем случае, я хотел бы отобразить содержимое file.gif по ссылке на file.jpeg. 

Если рассматривать частичное использование JavaScript, это могло бы выглядеть так: 
<pre><code>location @original {
        try_files $image_folder_1$uri  $image_folder_0$uri $image_folder_1$uri.replace(".jpeg", ".gif") $image_folder_0$uri.replace(".jpeg", ".gif") @errors;
}</code></pre> 

Как мне лучше организовать эту логику в Nginx?
  • 29 августа 2024 г. 16:34
Ответы на вопрос 2
В Nginx вы не можете использовать JavaScript для обработки логики, такой как замена строк, в директиве `try_files`. Вместо этого вы можете использовать несколько блоков `location` и директиву `if` для достижения желаемого поведения. 

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

1. Первым делом проверяем, существует ли файл с окончанием `.jpeg`.
2. Если существует, то проверяем, существует ли файл с окончанием `.gif`.
3. Если файл `.gif` существует, выполняем редирект на него; если нет - отправляем на обработку ошибки.

Вот пример конфигурации:

```nginx
server {
    ...

    location /images/ {
        # Путь к файлам
        set $image_folder_0 /path/to/your/images/0/;
        set $image_folder_1 /path/to/your/images/1/;

        # Обрабатываем запрос .jpeg
        location ~ \.jpeg$ {
            set $uri_gif $uri;
            # Меняем расширение с .jpeg на .gif
            if (-f $image_folder_1$uri_gif) {
                set $uri_gif $uri_gif;
            }
            if (-f $image_folder_0$uri_gif) {
                set $uri_gif $uri_gif;
            }
            if ($uri_gif ~* \.jpeg$) {
                # Смотрим, существует ли .gif
                set $uri_gif ${uri_gif/.jpeg/.gif};
                if (-f $image_folder_1$uri_gif) {
                    return 301 $uri_gif;
                }
                if (-f $image_folder_0$uri_gif) {
                    return 301 $uri_gif;
                }
            }
            # Если .gif не найден, отправляем на @errors
            return 404;
        }

        # Обрабатываем запрос .gif
        location ~ \.gif$ {
            try_files $image_folder_1$uri $image_folder_0$uri =404;
        }

        # Для остальных файлов используем общемасштабный блок
        location / {
            try_files $image_folder_1$uri $image_folder_0$uri =404;
        }
    }

    location @errors {
        # Обработка ошибок
        ...
    }
}
```

В этом примере:
- Мы определяем отдельные блоки для обработки `.jpeg` и `.gif`.
- Внутри блока для `.jpeg` мы проверяем, существует ли файл с соответствующим расширением `.gif` и выполняем редирект 301, если он существует.
- Если файл с расширением `.gif` не найден, возвращаем 404 (либо перенаправляем на `@errors`, если вам это нужно).
- Блоки `location` могут быть настроены в зависимости от вашего пути к изображениями.

Это не идеальное решение, так как использование `if` в конфигурации Nginx может быть ненадежным и неэффективным. Тем не менее, это наиболее простой и понятный способ достичь требуемой функциональности в данном случае.
Или хотя бы отобразить по ссылке на file.jpeg, сам file.gif

Создать новую переменную и заменить .jpeg на .gif с помощью map .
map $uri $gif {
default         $uri;
~^(.*)\.jpeg$  "$1.gif";
}


server {
    location @original {
        try_files $image_folder_1$uri  $image_folder_0$uri $image_folder_1$gif $image_folder_0$gif @errors;
    }
Похожие вопросы