random_index

Maxim Dounin mdounin на mdounin.ru
Чт Ноя 3 18:12:24 UTC 2011


Hello!

On Thu, Nov 03, 2011 at 09:35:53PM +0300, ola wrote:

> Здравствуйте, Maxim.
> 
> Вы писали 3 ноября 2011 г., 19:31:04:
> 
> >> Помогите, пожалуйста, разобраться с random_index.
> >> 
> >> server {
> >>     listen      127.0.0.1:80;
> >>     server_name localhost;
> >>     error_log   logs/error.log debug;
> >> 
> >>     location / {
> >>         root   /common/example.org/www;
> >>         index  index.html;
> >>     }
> >> 
> >>     location ~ ^/banner(\d+)/$ {
> >>         alias /common/example.org/adv/$1/;
> >>         random_index on;
> >>     }
> >> }
> >> 
> >> При  запросе  /banner2/ получается 404-я ошибка, nginx пытается отдать
> >> файл /common/example.org/www/banner2/1.html
> >> 
> >> Если  использовать  location ~ ^/banner(\d+)/ {} (без завершающего $),
> >> то  nginx  делает  10 внутренних редиректов и "Redirection limit of 10
> >> URL's reached"
> 
> > Если в директиве alias используются переменные, то она задаёт 
> > полный путь к файлу, который надо использовать.
> Максим,  объясните,  пожалуйста,  поподробнее.  Я  ж вроде и использую
> полный путь.

Значение "/common/example.org/adv/$1/" задаёт путь к каталогу, а 
не к конкретному файлу.

> > Должно сработать как-то так:
> 
> >     location ~ ^/banner(?<number>\d+)/(?<file>.*) {
> >         alias /common/example.org/adv/$number/$file;
> >         random_index on;
> >     }
> Это  немного  не  то. Если использовать ваш вариант, то получается что
> рандомные  имена  файлов  (?<file>.*)  надо  генерить  на  бекенде.  А
> хотелось бы использовать nginx для этой задачи.

Нет, не надо.  Модуль random index, увидив запрос к каталогу, 
сгенерирует внутренний редирект на случайный файл из каталога.  
Дальше нужно, чтобы этот перенаправленный запрос кто-то обработал.

В конфиге, который вы привели, всё происходит так:

1. Запрос "/banner2/" попадает в "location ~ ^/banner(\d+)/$".  
2. Модуль random index делает внутренний редирект на "/banner2/1.html".
3. Запрос "/banner2/1.html" попадает в "location /", пытается 
открыть файл /common/example.org/www/banner2/1.html (root + uri) и 
возвращает 404, т.к. такого файла нет.

Если написать, как вы пытались, "location ~ ^/banner(\d+)/" 
аналогичного содержания, то будет так:

1, 2 - то же самое.
3. Запрос "/banner2/1.html" попадает в "location ~ ^/banner(\d+)/". 
Тут nginx попытается открыть путь, заданный директивой alias (ибо 
она с переменными), а именно "/common/example.org/adv/2/".  
Обнаружит, что это - не файл, а каталог, и отдаёт 301 redirect с 
добавлением ещё одного '/' в конец uri.  Дальше браузер делает ещё 
один запрос, и цикл повторяется пока браузеру не надоест.

> По дебаг-логу видно что нгинкс сначала преобразовывает алиас, затем из
> списка   файлов   в   получившейся  директории  выбирает рандомный, но
> добавляет  выбранное  имя  файла  к  исходному (текущему?) uri, а не к
> пути,  полученному  из  алиаса.  Потом  делается внутренний редирект и
> начинается опять поиск нужного дlocation'a.

Да, именно так.  И index, и random_index работают по одному и тому 
же принципу: ищут подходящий индексный файл и делают внутренний 
редирект на него.  Это, в частности, позволяет использовать 
индексные файлы с отдельной обработкой, e.g. index.php.

Дополнительные детали можно почитать тут:
http://nginx.org/en/docs/http/request_processing.html

> Вот  если  бы  выбранное  рандомом  имя  добавить  к  преобразованному
> алиасу и остановиться на этом...
> Пробовала написать break; но видимо оно не для internal redirect.

Нужно просто сделать, чтобы получившийся после внутреннего 
редиректа запрос правильно обрабатывался.  Именно это и делает 
предложенный мной конфиг.

Maxim Dounin



Подробная информация о списке рассылки nginx-ru