Nginx rewrite url rules examples

NGINX Return directive

The easiest and cleaner way to rewrite an URL can be done by using the return directive. The return directive must be declared in the or location context by specifying the URL to be redirected.

1. NGINX Return directive in Server context

The return directive in server context is very useful in a situation where you have migrated your site to a new domain and you want to redirect all old URLs to the new domain.

Further, it also helps in canonicalization of URL by forcing your site to redirect to either www or non-www version.

The return directive in the above server context redirect URL destined to site to . As soon as NGINX receives an URL with www.olddomain.com, it stops processing the page and sends a 301 response code along with rewritten URL to the client.

The two variables used in the above return directive are and . The variable is used to define scheme of the URL (http or https) and the variable contains complete URI with parameters if any. Remember both the variable fetches this information from input URL while rewriting the URL.

2. Return directive in Location context

In some situation, you may want to redirect pages instead of redirecting domains. The return directive inside the location block enables you to redirect specific pages to a new location.

In the above example, whenever a request URI matches exactly with pattern , NGINX will redirect the same to the new location

You can also redirect everything for a specific path to a new location. The following example shows how to redirect all pages those falls under to .

Rewrite Break Flag в локальном контексте

В этом примере, мы поместили условие перезаписи внутри директивы location.

В этом примере директива location /data/, также совпадает с $ 1 в строке замены, приведенной ниже.

location /data/ {
 rewrite ^(/data/.*)/andreyex/(\w+)\.?.*$ $1/linux/$2.html break;
 return 403;
}

Это то, что случилось бы, если бы вы использовали флаг «last»:

  • Так что, если у вас был флаг «last», после первоначальной перезаписи URL, Nginx как правило, ищет следующую директиву rewrite для нового URL.
  • В этом случае, Nginx будет держать перенаправление на одни и те же данные о местоположении и продолжать обработку тех же правил перезаписи максимум 10 раз, и, потом, он возвратит код 500 ошибок.

Так как мы не хотим описанное выше поведение, мы использовали «break» в качестве флага, который просто остановит обработку перезаписи блоков.

Журнал (логи) преобразований mod_rewrite

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

Тема логов Apache сама по себе довольно объёмная, не будем на ней заострять внимание. Но необходимо упомянуть, что если вы работали с предыдущими версиями mod_rewrite и использовали директивы RewriteLog и RewriteLogLevel, то теперь их функциональность полностью заменена директивой LogLevel, которая настраивать логи всего веб-сервера и всех модулей.. По умолчанию LogLevel установлено показывать предупреждение, в конфигурационном файле Apache это строка:

По умолчанию LogLevel установлено показывать предупреждение, в конфигурационном файле Apache это строка:

LogLevel warn

Можно заменить эту строку на:

LogLevel error rewrite:trace2

Она означает, что для всего веб-сервера и остальных модулей настроен уровень журнала «error», т.е. показывать только ошибки и более важные сообщения, а для модуля mod_rewrite установлен уровень трассировки trace2.

mod_rewrite предлагает детальную запись его действий с уровней ведения журнала от trace1 до trace8. Уровень trace8 означает запись практически всех действий. Использование высоких уровней логов трассировки для mod_rewrite драматически замедлит ваш Apache HTTP сервер! Используйте уровень выше чем trace2 только для отладки!

Сообщения о работе mod_rewrite будут записываться в файл ошибок Apache (например, error.log). Чтобы из этого файла отфильтровать только строки, относящиеся к mod_rewrite, можно использовать поиск по «[rewrite:». К примеру, в Linux это можно делать примерно следующей командой:

tail -f /var/log/apache2/error.log | grep -F '[rewrite:'

Nginx Rewrite Flags Examples

The following are the 4 different Nginx Rewrite directive flags that you can use.

last: This flag will stop the processing of the rewrite directives in the current set, and will start at the new location that matches the changed URL.

rewrite ^(/data/.*)/geek/(\w+)\.?.*$ $1/linux/$2.html last;

break: This flag will stop the processing of the rewrite directives in the current set.

rewrite ^(/data/.*)/geek/(\w+)\.?.*$ $1/linux/$2.html break;

redirect: This flag will do a temporary redirection using 302 HTTP code. This is mainly used when the replacement string is not http, or https, or $scheme

permanent: This flag will do a permanent redirection using 301 HTTP code

rewrite ^ https://www.thegeekstuff.com$uri permanent;

Захват доступа Nginx Rewrite в Error Log File

По умолчанию, в любое время, при успешной перезапись в Nginx, он не регистрирует его в error.log.

Первоначально, когда вы пишете сложные правила перезаписи, вы действительно хотите убедиться, что Nginx будет делать rewrite согласно вашему требованию.

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

Для этого используйте директиву rewrite_log.

Добавьте следующие две строки в Nginx default.conf:

error_log /var/log/nginx/error.log notice;
rewrite_log on;

В приведенном выше:

Первая строка указывает местоположение файла error_log, где мы хотим, чтобы записывались сообщения о перезаписи

Обратите внимание, что сообщение перезаписи, типа уведомления. Таким образом, вы должны добавить «note» в конце этой линии, как показано выше.
rewrite_log on – Эта линия включает ведение журнала всех директив модуля ngx_http_rewrite_module в файл error_log.

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

 12345#12345: *1 "^(/data/.*)/andreyex/(\w+)\.?.*$" matches "/data/distro/andreyex/test", client: 192.168.101.1, server: localhost, request: "GET /data/distro/andreyex/test HTTP/1.1", host: "213.159.209.228"
 12345#12345: *1 rewritten data: "/data/distro/linux/test.html", args: "", client: 192.168.101.1, server: localhost, request: "GET /data/distro/andreyex/test HTTP/1.1", host: "213.159.209.228"

В приведенном выше строк лога:

  • Первая линия показывает две вещи 1) Входящий URL 2) используемые правила перезаписи
  • В 1-й линии, показывается входящий URL (т.е. запрос). В этом примере запрос: «GET /data/distro/andreyex/test»
  • В 1-й линии, он также показывает правила перезаписи Nginx, которому соответствовал этот входящий запрос. В этом примере правило перезаписи используемой Nginx является: “^(/data/.*)/andreyex/(\w+)\.?.*$”
  • Во 2-й линии, показывает переписанный переведенный URL, который использовался в Nginx после применения правила перезаписи. В этом примере, переведенный URL переписан: /data/distro/linux/test.html

Пример использования Nginx Rewrite $ 1, $ 2, ..

Ниже приведен пример директивы Nginx Rewrite:

rewrite ^(/data/.*)/andreyex/(\w+)\.?.*$ $1/linux/$2.html last;

Например:

  • url/data/distro/andreyex/test.php перепишет в виде url/data/distro/linux/test.html
  • В этом примере, когда вы вызываете оригинальный URL с test.php из браузера, он будет переписан на основе вышеприведенного правила перезаписи и будет указывать страницу test.html из /data/distro/linux/

В приведенном выше правила перезаписи:

$ 1 и $ 2 будет фиксировать соответствующие строки из исходного URL, которые не изменяется
$ 1 в замещающей строке заместит находится внутри 1-й скобки () в reg-ехе. В нашем примере, $1 в /data/
Точно так же $ 2 заместит находится внутри 2 скобки () в reg-ехе. Таким образом, $ 2 в (\w+), так что любое слово, которое приходит после /andreyex/ в оригинальном URL. В нашем примере, $ 2 является test
last – этот флаг убедиться, чтобы остановить поиск директивы Rewrite в текущем местоположении или блоке и использовать измененный URI (т.е. переписан URI) и искать новое место для любых дальнейших директив Rewrite.
*$ – Указывает на расширение в исходном URL

Обратите внимание, что здесь, расширение от исходного URL будет заменено на .html в URL путем Rewrite. Таким образом, даже если вы вызываете .php в оригинальном URL, он будет показывать только файл .html в переписанной URL.

В то время как правила перезаписи Nginx делают подобные вещи, как Apache, есть еще много различий в плане того, как вы пишете правило перезаписи в Nginx.

Для чего нужен mod_rewrite / Что умеет mod_rewrite

Слово «rewrite» в названии модуля буквально означает «перезапись». Эта «перезапись» относится к URL (адресу сайта, страницы, файла). Перезапись (преобразование) происходит между тем, что введено в строке браузера пользователя (фактически, отправлено на веб-сервер) и тем, что веб-сервер получит на самом деле.

Наглядным примером применения mod_rewrite являются ЧПУ (аббр. от «человекопонятный URL») — URL-путь, состоящий из понятных слов, вместо идентификаторов, и отражающий файловую структуру сайта. Например, вместо /c14/3/97/ или /index.php?cat=10&subcat=2&id=41 будет /product/phone/Samsung/.

Человекопонятные пути улучшают удобство использования, Кроме того, позволяют по названию ссылки заранее предполагать содержимое страницы по ней, и представлять структуру сайта.

Это очень популярное, но не единственное применение mod_rewrite. Этот модуль умеет делать перезапись на основе разных данных: к примеру, на основе типа браузера. Это позволяет показывать разные страницы в зависимости от типа браузера, IP адреса, языка пользователя, установленных кукиз и т.д.

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

mod_rewrite умеет запрещать доступ к определённым ресурсам, как по определённому условию, так и безусловно. Т.е. вы можете настроить контроль доступа, закрыв определённые страницы для всех пользователей, либо на основе их стран, языка, веб-браузера и т.д.

На самом деле – это не всё, что умеет mod_rewrite! И даже в этом мануале вы встретитесь с дополнительными примерами применения mod_rewrite.

Прежде чем мы перейдём к теории и практики использования mod_rewrite, нужно включить модуль mod_rewrite для веб-сервера, либо убедиться, что mod_rewrite уже включен. Если вы используетесь shared (совместным) хостингом, то у большинства хостеров этот модуль включен по умолчанию. Ниже показано, как включить этот модуль на своём собственном локальном (домашнем) сервере, либо веб-сервере на VPS.

Все стандартные редиректы в nginx

Рассмотрю типовой пример, когда у нас одновременно присутствуют следующие редиректы:

  1. С http на https.
  2. С www на без www для обоих протоколов.
  3. Без слеша на конце на урл со слешем.

Наша цель будет реализовать все преобразования url в одном месте и выдать клиенту только один 301-й редирект.

server {
    listen 443 ssl http2;
    server_name site.ru;
    root /web/sites/site.ru/www/;
    index index.php index.html index.htm;
    access_log /web/sites/site.ru/log/access.log main;
    error_log /web/sites/site.ru/log/error.log;

    ssl_certificate		/etc/letsencrypt/live/site.ru/fullchain.pem;
    ssl_certificate_key		/etc/letsencrypt/live/site.ru/privkey.pem;

    location / {
	rewrite ^(*)$ $1/ permanent;
	try_files $uri/ /index.php?$args;
	}

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|webp|ico|woff|txt)$ {
	access_log off;
	expires max;
	}

    location ~* ^/(\.ht|xmlrpc\.php)$ {
	return 404;
	}

    location ~ \.php$ {
	try_files  $uri =404;
	fastcgi_pass   unix:/var/run/php-fpm/php7-fpm.sock;
	fastcgi_index index.php;
	fastcgi_param DOCUMENT_ROOT /web/sites/site.ru/www/;
	fastcgi_param SCRIPT_FILENAME /web/sites/site.ru/www$fastcgi_script_name;
	fastcgi_param PATH_TRANSLATED /web/sites/site.ru/www$fastcgi_script_name;
	include fastcgi_params;
	fastcgi_param QUERY_STRING $query_string;
	fastcgi_param REQUEST_METHOD $request_method;
	fastcgi_param CONTENT_TYPE $content_type;
	fastcgi_param CONTENT_LENGTH $content_length;
	fastcgi_param HTTPS on;
	fastcgi_intercept_errors on;
	}

    location = /favicon.ico {
	log_not_found off;
	access_log off;
	}

    location = /robots.txt {
	allow all;
	log_not_found off;
	access_log off;
	}
}

server {
    listen 443 ssl http2;
    server_name www.site.ru;

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|webp|ico|woff|txt)$ {
	return 301 https://site.ru$request_uri;
    }
    
    location / {
	rewrite ^/(.*)/$ /$1;
	return 301 https://site.ru$uri/;
    }
}

server {
    listen 80;
    server_name site.ru www.site.ru;

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|webp|ico|woff|txt)$ {
	return 301 https://site.ru$request_uri;
    }
    
    location / {
	rewrite ^/(.*)/$ /$1;
	return 301 https://site.ru$uri/;
    }
}

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

Подстановка RewriteRule

Подстановка правила перезаписи – это строка, которая заменяет оригинальный URL-путь, который совпал с Шаблоном. В качестве подстановки может быть:

путь в файловой системе

Указывает местоположение в файловой системе ресурса, который будет доставлен клиенту. Подстановки обрабатываются как путь к файловой системе, когда правило настроено в контексте сервера (virtualhost), и первый компонент пути в подстановке существует в файловой системе.

URL-путь

Относительный DocumentRoot путь к ресурсу, который будет обслуживаться

Обратите внимание, что mod_rewrite пытается угадать, указали ли вы путь файловой системы или URL-путь, проверяя, существует ли первый сегмент пути в корне файловой системы. Например, если вы укажете строку Подстановки /www/file.html, это будет рассматриваться как путь URL-адреса, если директория с именем www не существует в корне вашей файловой системы (или в случае использования перезаписи в файле .htaccess относительно вашего корня документов), в последних случаях это будет рассматриваться как путь в файловой системе

Если вы хотите, чтобы другие директивы сопоставления URL (такие как Alias) применялись к результирующему URL-адресу, используйте флаг , как описано в третьей части данного руководства.

Абсолютный URL

Если указан абсолютный URL, mod_rewrite проверяет, совпадает ли имя хоста с текущим хостом. Если да, то схема и имя хоста отбрасываются и результирующий путь трактуется как URL-путь. В противном случае, выполняется внешний редирект (перенаправление) для заданного URL. Для принудительного внешнего редиректа на текущий хост (чтобы запрашиваемая страница поменяла адрес на другую страницу этого же хоста), смотрите флаг , описанный далее.

— (чёрточка)

Чёрточка говорит о том, что не должна выполняться какая-либо подстановка (существующий путь должен быть пропущен нетронутым). Это используется когда нужно применить флаг (смотрите далее) без изменения пути.

В дополнении к простому тексту, строка Подстановки может включать:

  1. ($N) на шаблон RewriteRule
  2. (%N) на последний совпавший шаблон RewriteCond
  3. серверные переменные как в тестовых строках условия правила (%{VARNAME})
  4. вызов функции сопоставления (mapping) (${mapname:key|default})

Perl + FastCGI + nginx

Полноформатная статья: FastCGI-приложение на Perl

Примеры

  • Способ 1 — запустить mod_fastcgi на бакенде с apache и редиректить туда.
  • Способ 2 (оптимальный)- по аналогии с php, запустить через spawn-fcgi (из комплекта lighttpd) нужное число Perl процессов.
  • Способ 3 — запуск perl скрипта как fastcgi-сервера. Например (для паралелльного запуска нескольких обработчиков нужно использовать FCGI::ProcManager):
#!/usr/bin/perl
use strict;
use FCGI;
# use FCGI::ProcManager;
# my $proc_manager = new FCGI::ProcManager({ n_processes => 2, die_timeout => 10 });
my $socket = FCGI::OpenSocket( ":9000", 5 ); # 5 - разрем очереди запросов.
my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket );
# В случае с ProcManager цикл обработки запросов будет выглядеть примерно так:
# $proc_manager->pm_manage();
# while (my $cgi = CGI::Fast->new()) {
#   $proc_manager->pm_pre_dispatch();
#   # ...
#   $proc_manager->pm_post_dispatch();
#}
my $count;
while( $request->Accept() >= 0 ) {
   print "Content-type: text/html\r\n\r\n";
   print ++$count;
}
FCGI::CloseSocket( $socket );

Настройка nginx

location /cgi-bin/script.fcgi {
	fastcgi_pass localhost:9000;
	fastcgi_root /path/to/cgi-bin/script.fcgi;
}

Пример с codemongers.com:

#!/usr/bin/perl
use FCGI;
#perl -MCPAN -e 'install FCGI'
use Socket;
#this keeps the program alive or something after exec'ing perl scripts
END() { } BEGIN() { }
*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; }; eval q{exit}; if () { exit unless  =~ /^fakeexit/; } ;
&main;
sub main {
	#$socket = FCGI::OpenSocket( ":3461", 10 ); #use IP sockets
	$socket = FCGI::OpenSocket( "/var/run/nginx/perl_cgi-dispatch.sock", 10 ); #use UNIX sockets - user running this script must have w access to the 'nginx' folder!!
	$request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket );
	if ($request) { request_loop()};
		FCGI::CloseSocket( $socket );
}
sub request_loop {
	while( $request->Accept() >= 0 ) {
	   #processing any STDIN input from WebServer (for CGI-POST actions)
	   $stdin_passthrough ='';
	   $req_len = 0 + $req_params{'CONTENT_LENGTH'};
	   if (($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){
					while ($req_len) {
						$stdin_passthrough .= getc(STDIN);
						$req_len--;
					}
		}
		#running the cgi app
		if ( (-x $req_params{SCRIPT_FILENAME}) &&  #can I execute this?
			 (-s $req_params{SCRIPT_FILENAME}) &&  #Is this file empty?
			 (-r $req_params{SCRIPT_FILENAME})     #can I read this file?
		){
			foreach $key ( keys %req_params){
			   $ENV{$key} = $req_params{$key};
			}
			#http://perldoc.perl.org/perlipc.html#Safe-Pipe-Opens
			open $cgi_app, '-|', $req_params{SCRIPT_FILENAME}, $stdin_passthrough or print("Content-type: text/plain\r\n\r\n"); print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n";
			if ($cgi_app) {print <$cgi_app>; close $cgi_app;}
		}
		else {
			print("Content-type: text/plain\r\n\r\n");
			print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";
		}
	}
}
http {
	root  /var/www/htdocs;
	index index.html;
	location ~ ^/cgi-bin/.*\.cgi$ {
		fastcgi_pass  unix:/var/run/nginx/perl_cgi-dispatch.sock;
		fastcgi_index index.cgi;
		fastcgi_param SCRIPT_FILENAME /var/www/cgi-bin$fastcgi_script_name;
		fastcgi_param QUERY_STRING     $query_string;
		fastcgi_param REQUEST_METHOD   $request_method;
		fastcgi_param CONTENT_TYPE     $content_type;
		fastcgi_param CONTENT_LENGTH   $content_length;
		fastcgi_param GATEWAY_INTERFACE  CGI/1.1;
		fastcgi_param SERVER_SOFTWARE    nginx;
		fastcgi_param SCRIPT_NAME        $fastcgi_script_name;
		fastcgi_param REQUEST_URI        $request_uri;
		fastcgi_param DOCUMENT_URI       $document_uri;
		fastcgi_param DOCUMENT_ROOT      $document_root;
		fastcgi_param SERVER_PROTOCOL    $server_protocol;
		fastcgi_param REMOTE_ADDR        $remote_addr;
		fastcgi_param REMOTE_PORT        $remote_port;
		fastcgi_param SERVER_ADDR        $server_addr;
		fastcgi_param SERVER_PORT        $server_port;
		fastcgi_param SERVER_NAME        $server_name;
	}
}

Пример с kiev.pm.org

use FCGI;
use FCGI::ProcManager;
use CGI;
my $proc_manager = FCGI::ProcManager->new({ n_processes => 10 });
my $socket = FCGI::OpenSocket(":9000", 5);
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
$proc_manager->pm_manage();
my $count = 0;
while($request->Accept() >= 0) {
$count++;
print <<TEXT;
Content-Type: text/html
<h1>hello</h1>
$count
<hr>
TEXT
	print "$_ = $ENV{$_}<br>\n" foreach sort keys %ENV;
	print "<hr>\n";
	my $query = CGI->new();
	print "$_ = ", $query->param($_), "<br>\n" foreach sort $query->param();
}
FCGI::CloseSocket($socket);

Joomla

server {
        listen 80;
        server_name YOUR_DOMAIN;
        server_name_in_redirect off;

        access_log /var/log/nginx/localhost.access_log main;
        error_log /var/log/nginx/localhost.error_log info;

        root PATH_ON_SERVER;
        index index.php;
        # Support Clean (aka Search Engine Friendly) URLs
        location / {
                try_files $uri $uri/ /index.php?q=$uri&$args;
        }

        index index.php index.html index.htm default.html default.htm;
        # deny running scripts inside writable directories
        location ~* /(images|cache|media|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
                return 403;
                error_page 403 /403_error.html;
        }

        location ~ .*.php$ {
            include /etc/nginx/fastcgi.conf;
            fastcgi_pass  127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }

        # caching of files 
        location ~* \.(ico|pdf|flv)$ {
                expires 1y;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|swf|xml|txt)$ {
                expires 14d;
        }

}

If Context and Rewrite Directive

The following few examples illustrates that we can use rewrite inside the if directive.

You can do a conditional rewrite based by doing some if condition comparison using variables like $scheme, $http_host, $http_user_agent, etc, as shown below:

if ($scheme = "http") {
  rewrite ^ https://www.thegeekstuff.com$uri permanent;
}

if ($http_host = thegeekstuff.com) {
  rewrite  (.*)  https://www.thegeekstuff.com$1;
}

if ($http_user_agent = MSIE) {
    rewrite ^(.*)$ /pdf/$1 break;
}

Please note that there are better ways to achieve the end-result of the above examples. The above examples are just given to show that we can add rewrite directive inside if statement in the nginx config file.

Please note that you can also set the value of the following two parameters to either on or off in your nginx config file:

server_name_in_redirect on 
port_in_redirect off

Что такое mod_rewrite

mod_rewrite является одним из самых часто используемых модулей веб-сервера Apache. При этом он является и самым непонятным: очень многие ищут подходящие под свои нужды примеры выражений mod_rewrite и копируют их без полного понимания, как именно это работает и что именно происходит при обработке адресов.

Эта инструкция призвана это исправить: если вы совершенно не понимаете даже азов работы mod_rewrite, то это руководство поможет вам разобраться; если вы уже в общих чертах понимаете, как происходит поиск совпадений и формирование нового адреса, то эта инструкция поможет вам систематизировать ваши знания и узнать новые сложные или необычные примеры использования mod_rewrite.

mod_rewrite предоставляет возможность динамически изменять входящие URL-запросы, основываясь на правилах, использующих регулярные выражения. Это позволяет вам сопоставлять произвольные URL-адреса к вашей внутренней структуре URL любым способом. По умолчанию mod_rewrite сопоставляет URL-адрес пути к файловой системе. Однако он также может использоваться для перенаправления одного URL-адреса на другой URL-адрес или для вызова внутренней прокси передачи.

mod_rewrite предоставляет гибкий и мощный способ манипулирования URL-адресами, используя неограниченное количество правил. Каждое правило может иметь неограниченное количество прикреплённых условий правила, позволяя вам переписать URL на основе переменных сервера, переменных среды, заголовков HTTP, метки времени, запросы к внешним базам данных и различных других внутренних программ и обработчиков.

Правила перезаписи могут оперировать полными URL, включая path-info (информацию о пути) и строку запроса; отдельные правила можно настроить для использоваться в контексте всего сервера, отдельного для каждого виртуального хоста или для каждой директории (папки). Правила перезаписи могут вести к последующим правилам, внутренним подпроцессам, внешним перенаправлениям запросов или проксированию, в зависимости от флагов, которые вы добавили к правилам.

Поскольку mod_rewrite такой мощный, его изучение требует времени. Функциональность mod_rewrite пересекается с некоторыми другими модулями Apache и решение, что именно использовать, за вами. В этой инструкции дан подробный разбор всех возможностей mod_rewrite и показано много примеров, как использовать этот модуль, а когда лучше использовать другие альтернативы.

Порядок обработки правил mod_rewrite

Порядок обработки правил mod_rewrite является далеко не очевидным. Правила mod_rewrite составляются примерно в таком порядке:

RewriteEngine on
 
RewriteBase /
# uncomment this line if web-base dir not root
# RewriteBase /you-web-base-dir
RewriteCond %{что_сравнивать} с_чем_сравнивать 
RewriteRule исходный_url целевой_url 

Теперь чуть подробнее:

  • RewriteEngine — должна быть одна;
  • RewriteBase — может пригодится при использовании в правилах относительных ссылок, но если относительные ссылки относятся к корню каталога, то данная директива может не использоваться, теоретически может использоваться многократно перед каждым из правил;
  • RewriteCond — условие, которое должно быть соблюдено перед выполнением правила, условий может быть несколько;
  • RewriteRule — собственно само правило, которое выполняется при соблюдении условия.

Порядок размещения правил .htaccess важен потому что механизм преобразований обрабатывает их в специальном порядке. Строчка за строчкой сначала просматриваются RewriteRule директивы и при соответствии URL шаблону (Pattern, исходный_url) конкретного правила проверяются условия (RewriteCond директивы) относящиеся к этому правилу. Условия (RewriteCond) всегда должны быть перед правилами (RewriteRule)! На рис. ниже показан порядок обработки правил mod_rewrite.

Как видно, Текущий URL сначала сравнивается с Шаблон правила и при совпадении с шаблоном проверяет условия, если Текущий URL удовлетворяет условиям, то к нему применяется правило и Преобраз. URL идёт дальше на обработку если не указан флаг (last).

Флаг нужно использовать для каждого правила, разумеется если дальнейшая трансформация URL не требуется.

Далее директива «» не будет упоминаться в примерах, — т.е. будем подразумевать, что она уже была добавлена ранее и в дальнейшем дублировать её мы не будем.

Capture Nginx Rewrite Hits in Error Log File

By default, anytime Nginx does successful rewrite, it doesn’t log it in the error.log.

Initially when you are writing complex rewrite rules, you really want to make sure that Nginx is doing the rewrite as per your requirement.

For this, you should enable the rewrite log, which will write a log entry anytime nginx does a successful rewrite using any one of the rewrite directive in the configuration file.

For this, use the rewrite_log directive and set it to on.

Add the following two lines to your nginx default.conf:

error_log /var/log/nginx/error.log notice;
rewrite_log on;

In the above:

  • The first line indicates the location of the error_log file where we want to write the rewrite messages. Please note that a rewrite message is of type notice. So, you have to add “note” at the end of this line as shown above.
  • rewrite_log on – This line enables logging of all the directives of ngx_http_rewrite_module modules to the error_log file.

After the above change, you’ll started seeing lines like this which clearly shows which specific rewrite rule was used in translating the incoming URL. This also will show the final translated URL in the log entry.

 14385#14385: *1 "^(/data/.*)/geek/(\w+)\.?.*$" matches "/data/distro/geek/test", client: 192.168.101.1, server: localhost, request: "GET /data/distro/geek/test HTTP/1.1", host: "192.168.101.10"
 14385#14385: *1 rewritten data: "/data/distro/linux/test.html", args: "", client: 192.168.101.1, server: localhost, request: "GET /data/distro/geek/test HTTP/1.1", host: "192.168.101.10"

In the above:

  • The 1st line shows two things 1) Incoming URL 2) Rewrite rule used
  • In the 1st line, it shows the incoming URL (i.e the request). In this example, the request is: “GET /data/distro/geek/test”
  • In the 1st line, it also shows the Nginx rewrite rule that matched this incoming request. In this example, the rewrite rule used by nginx is: “^(/data/.*)/geek/(\w+)\.?.*$”
  • In the 2nd line, it shows the rewritten translated URL that was used by Nginx after applying the rewrite rule. In this example, the translated rewritten URL is: /data/distro/linux/test.html

If и Директива Rewrite

Следующие несколько примеров показывают, что мы можем использовать Rewrite внутри директивы if.

Вы можете сделать условное переписывание на основе if, если условие сравнения с использованием переменных, таких как $scheme, $http_host, $http_user_agent, и т.д., как показано ниже:

if ($scheme = "http") {
  rewrite ^ https://www.andreyex.ru$uri permanent;
}

if ($http_host = andreyex.ru) {
  rewrite  (.*)  https://www.andreyex.ru$1;
}

if ($http_user_agent = MSIE) {
    rewrite ^(.*)$ /pdf/$1 break;
}

Обратите внимание, что есть лучшие способы для достижения конечного результата приведенных выше примеров. Приведенные выше примеры просто даны для того, чтобы показать, что мы можем добавить директиву rewrite внутри, если заявление в файле конфигурации Nginx

Обратите внимание, что вы можете также установить значение двух следующих параметров или выключить в файле конфигурации Nginx:

server_name_in_redirect on 
port_in_redirect off

Opencart 3

location /image/data {
	autoindex on;
}    

location /admin {
	index index.php;
}
	
location = /sitemap.xml {
	rewrite ^(.*)$ /index.php?route=feed/google_sitemap break; 
	} 

location = /googlebase.xml {
	rewrite ^(.*)$ /index.php?route=feed/google_base break; 
} 

location / {
	try_files $uri $uri/ @opencart;
}
    
location @opencart {
	rewrite ^/en/(*) /index.php?_route_=$1&lang=en-gb last;
	rewrite ^/en$ /index.php?_route_=$1&lang=en-gb last;
	rewrite ^/cz/(*) /index.php?_route_=$1&lang=cs-cz last;
	rewrite ^/cz$ /index.php?_route_=$1&lang=cs-cz last;
	rewrite ^/(.+)$ /index.php?_route_=$1 last;
}
	
location = /favicon.ico {
	log_not_found off;
	access_log off;
}

location = /robots.txt {
	allow all;
	log_not_found off;
	access_log off;
}

location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|\.php_ {
	deny all;
}

location ~ /\. {
	deny all;
	access_log off;
	log_not_found off;
}
    
location ~*  \.(jpg|jpeg|png|gif|css|js|ico)$ {
	expires 7d;
	log_not_found off;
}
    
location ~ \.php$ {
	try_files $uri =404;
	include /etc/nginx/fastcgi_params;
	fastcgi_pass 127.0.0.1:9000;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
	}

Итоги

mod_rewrite является мощным инструментом и с его помощью можно творить чудеса, — это факт! В этой статье не так много примеров, но их валом в сети, а вот материала о том, что к чем и почему в стиле как для полных идиотов практически не встретить. Возможно папизже позднее на эту страницу будут добавлены ещё примеры использования mod_rewrite.

В этой статье я постарался максимально доходчиво изложить (надеюсь мне это удалось) базовые принципы работы чудо-модуля mod_rewrite, в стиле как для полных идиотов (в хорошем смысле слова;), имхо на собственном опыте знаю как оно иногда тяжко осваивать что-то с ноля и когда маны и принципы этого что-то описаны общими туманными фразами и глубоко техническими терминами.

Ссылки по теме mod_rewrite

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Мой редактор ОС
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: