Nginx, SSI и использование переменных

Я использую SSI в Nginx и мне это нравится. Но есть проблема.


Дано


Есть страница, которую почти полностью можно кешировать на час. В нее нужно встраивать блок со случайной картинкой. Заголовок страницы () зависит от картинки.


Решение


Backend выдает отдельно страницу /page/ и случайный блок /random/. Случайный блок хитро кешируется на 30 секунд, а страница — просто, но на час. Далее Nginx.SSI вставляет блок в страницу.


Проблема


Я не знаю, как вставить title в страницу. Текст заголовка — это название случайной картинки. Она вставляется внутри body, поэтому переменные, которым я присваиваю значение внутри /random/, еще не инициализированы в момент вывода title.

Я придумал, как обойти проблему:

random.html

    <!--# set var="title" value="бла-бла" -->
    <img src="bla-bla.jpg" />


page.html

    <!-- HTML-комментарий
        <!--# include virtual="/random/?$args" wait="yes" -->
    -->
    <head>
        <title><!--# echo var="title" encoding="none" default="без заголовка" --></title>
    </head>
    <body>
        ....
        <!--# include virtual="/random/?$args" -->
    </body>


Видно, что блок /random/ включается в страницу два раза. Это плохо, поскольку на самом деле блок содержит не только картинку но и приличное количество верстки, которая зависит от картинки. Весь этот код дублируется на странице и ест мой трафик.

Очевидно, можно было бы сохранить код, возвращаемый первым вызовом в переменной, а затем вставить в страницу значение этой переменной.

page.html

    <!-- HTML-комментарий
        <!--# include virtual="/random/?$args" wait="yes" set="random_html" -->
    -->
    <head>
        <title><!--# echo var="title" encoding="none" default="без заголовка" --></title>
    </head>
    <body>
        ....
        <!--# echo var="random_html" encoding="none" default="" -->
    </body>


Но в этом случае (если использовать параметр set у директивы include) значения переменных, установленных внутри /random/ не передаются в /page/ — title оказывается пустым. У меня есть подозрение, что это досадный баг. Напишу об этом разработчику. Правда, не знаю, куда именно…

Можно положить верстку в отдельную переменную, но будут проблемы с экранированием всяких там $ и чего-то еще.

Еще пробовал сделать замену при помощи sub_filter, но она, видимо, выполняется до SSI и тамошних переменных не видит.


Внимание, вопрос


Как сделать все это за один include?
  • Вопрос задан
  • 6318 просмотров
Пригласить эксперта
Ответы на вопрос 2
@Demetros
Ваш вариант с двумя переменными по-моему единственно возможный.
Но для хранения в SSI переменных больших кусков текста нужно воспользоваться недокументированной директивой ssi_value_length, которая по умолчанию равна 256 байтам и этого скорее всего не хватает для хранения вашего html-кода (об этом должны быть сообщения в error-логе):

location /random/ {
  ...
  ssi_value_length 32k;
}
Ответ написан
там в nginx в ssi есть параметр, который позволяет присвоить результат include переменной. делаем это в начале страницы, получаем переменную с кодом картинки и переменнут с тайтлом. вставляем их там где надо в страницу и дело в шляпе
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы