try_files + subrequest + proxy-handler

Maxim Dounin mdounin at mdounin.ru
Tue Apr 21 19:11:35 UTC 2015


Hello!

On Mon, Apr 20, 2015 at 05:39:18PM +0300, Eugene Mychlo wrote:

> Добрый день,
> 
> Столкнулся со странной поведением nginx при использовании subrequest в сочетании с try_files с proxy-хэндлером.
> В приведенной ниже конфигурации, ожидалось, что при наличии файла  /tmp/tres,  на запрос
> 
> http://127.0.0.1:8080/uno
> 
> nginx вернет строку "uno  duo " или  "tres tres ", но никак не  "uno  tres ".
> 
> Т.е. URI основного запроса передается без изменений (как и описано в документации), а подзапроса - нет.
> Ситуация воспроизводится на nginx версий 1.7.9 - 1.7.12.
> 
> Отсюда вопрос: является ли подобное поведение задуманным или это бага?
> Будет ли меняться?  И не стоит ли отметить это в документации?
> 
> 
> 
>     server {
>         listen       8081;
>         default_type text/html;
> 
>         location /uno {   return 200 "uno  ";   }
>         location /duo {   return 200 "duo  ";   }
>         location /tres {   return 200 "tres  ";   }
>     }
> 
> 
>     server {
>         listen       8080;
> 
>         location / {
>             root /tmp;
>             try_files /tres =404;
>             proxy_pass http://127.0.0.1:8081;
>             add_after_body /duo;
>         }
>     }

Наблюдаемый эффект - следствие того, что try_files меняет URI 
запроса.  (Мне лично кажется, что это - скорее неправильное 
поведение.  По хорошему, ему следует оставлять URI тем же, а 
менять только соответствующий текущему URI файл.  Но именно так 
оно сейчас реализовано, и не совсем понятно, хотим ли мы это 
менять.  Когда делался try_files - какая-либо дальнейшая 
обработка, которая бы зависила от URI, просто не предполагалась, 
насколько я понимаю.)

При этом try_files используется как для обработки основного 
запроса, так и для подзапроса.   Т.е. $uri в обоих случаях в 
момент проксирования - "/tres".

Однако при этом URI основного запроса считается низменённым 
(потому что по хорошему try_files URI менять не должен, см. выше), 
и соответственно соединение с бекендом (ибо proxy_pass без URI) 
использует исходный URI запроса в том виде, как он был передан 
клиентом, "/uno".  В подзапросе же URI заведомо изменён, и 
proxy_pass в соответствии с документацией использует 
нормализованный URI запроса целиком, т.е. "/tres".

Возможных решений представляется два:

- переделать try_files так, чтобы URI не менялся, тогда будет "uno 
  duo";

- узаконить текущее поведение try_files и при изменении им URI 
  сбрасывать флаг r->valid_unparsed_uri, тогда будет "tres tres".

Мне лично более правильным кажется первый вариант.  Но, возможно, 
существуют какие-то ситуации, когда менять URI - всё-таки 
правильнее, надо подумать.

Ну и да, текущее поведение - явно баг, имеет смысл добавить на 
trac.nginx.org.

-- 
Maxim Dounin
http://nginx.org/



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