Opened 6 years ago

Closed 6 years ago

#1584 closed defect (invalid)

rewrite qure — at Version 1

Reported by: ser891@… Owned by:
Priority: major Milestone:
Component: nginx-core Version: 1.14.x
Keywords: Cc: ser891@…
uname -a: Linux HOST 4.1.12-61.1.33.el7uek.x86_64 #2 SMP Thu Mar 30 18:45:51 PDT 2017 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.14.0
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC)
built with OpenSSL 1.0.2o 27 Mar 2018
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --add-module=/opt/nginx/nginx-module-vts-master/ --add-module=/opt/nginx/lua-nginx-module-master/ --add-module=/opt/nginx/testcookie-nginx-module-master --add-module=/opt/nginx/nginx_upstream_check_module-master --add-module=/opt/nginx/nginx-upstream-dynamic-servers-master --add-module=/opt/nginx/nginx-goodies-nginx-sticky-module-ng-08a395c66e42 --with-pcre-jit --with-http_image_filter_module --with-http_ssl_module --with-openssl=/opt/nginx/openssl-1.0.2o/ --with-pcre=/opt/nginx/pcre-8.41/ --with-http_sub_module --with-http_realip_module --with-http_addition_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_v2_module --with-ipv6 --with-debug

Description (last modified by Maxim Dounin)

        map $uri$is_args$args $red_www_to_www {
                default 1;
                "~^/test/\?ewewewe"     "/ru/ru/arg?34344";
        }
server {
        listen        80 default;    
        if ($red_www_to_www != 1 ) { rewrite ^(.*) 
                https://$host$red_www_to_www permanent; break; }
        }

При таких настройках происходит это
https://www.host.ru/test/?ewewewe > https://www.host.ru/ru/ru/arg?34344?ewewewe
а должнобыть
https://www.host.ru/test/?ewewewe > https://www.host.ru/ru/ru/arg?34344
Добавляется лишний args "?ewewewe" при редиректе

А если сделать так.

server {
        listen        80 default; 

        set $red_www_to_www  "/ru/ru/arg?34344";
   
        if ($red_www_to_www != 1 ) { rewrite ^(.*) 
                https://$host$red_www_to_www permanent; break; }
        }

При таких настройках происходит это
https://www.host.ru/test/?ewewewe > https://www.host.ru/ru/ru/arg?34344&ewewewe
То вместо ? появляется &

Change History (1)

comment:1 by Maxim Dounin, 6 years ago

Description: modified (diff)
Resolution: invalid
Status: newclosed

Директива rewrite работает с URI запроса без аргументов, аргументы - по умолчанию сохраняются от исходного запроса. Цитата из документации:

Если в строке замены указаны новые аргументы запроса, то предыдущие аргументы запроса добавляются после них. Если такое поведение нежелательно, можно отказаться от этого добавления, указав в конце строки замены знак вопроса, например:

rewrite ^/users/(.*)$ /show?user=$1? last;

Что касается ...?34344?ewewewe в одном случае, и ...?34344&ewewewe в другом, то в обоих приведённых случаях результат будет ...?34344?ewewewe. Результат ...?34344&ewewewe можно получить, если символ ? будет непосредственно в строке замены (во втором агрументе rewrite):

    set $red_www_to_www  "/ru/ru/arg";
    rewrite ^ https://$host$red_www_to_www?34344 permanent;

Это связано с тем, что nginx не пытается искать символ '?' внутри подставляемых переменных, а рассматривает их как часть соответствующей части URL. Если же символ '?' используется явно в строке замены, то nginx знает, что в строке замены есть аргументы, и добавляет к ним исходные аргументы запроса через символ '&'.

Вообще в рассматриваемом случае - проще и правильнее всего вместо rewrite использовать директиву return:

return 301 https://$host$red_www_to_www;

Директива return предназначена для возврата клиенту ровно того, что просили вернуть, а не для замены частей URI, и соответственно не пытается как-либо обрабатывать и дополнять переданную ей строку.

Note: See TracTickets for help on using tickets.