This page has been robot translated, sorry for typos if any. Original content here.

Wie funktioniert mod_rewrite? Erlaubnis für die Fortsetzung

Как на самом деле работает mod_rewrite. Пособие для продолжающих

Dieser Artikel entstand aus der Idee der Weiterbildung unserer technischen Supportmitarbeiter, die mit mod_rewrite arbeiten. Die Praxis hat gezeigt, dass nach dem Studium der verfügbaren in einer großen Anzahl von Lehrbüchern auf Russisch, die Unterstützung ist gut gegeben, die Lösung der Vorlage Aufgaben, aber hier erfolgt die unabhängige Zusammenstellung der Regeln durch Versuch und Irrtum. Das Problem ist, dass es für ein gutes Verständnis der Arbeit von mod_rewrite notwendig ist, die ursprüngliche englischsprachige Dokumentation zu studieren, danach - entweder zusätzliche Erklärungen oder Stunden von Experimenten mit RewriteLog.

Der Artikel beschreibt den Mechanismus der Operation mod_rewrite. Wenn Sie die Prinzipien seiner Arbeit verstehen, können Sie die Funktionsweise jeder Anweisung klar verstehen und sich klar vorstellen, was bei der Verarbeitung von Anweisungen irgendwann in mod_rewrite passiert.

Ich nehme an, dass der Leser bereits weiß, was mod_rewrite ist, und ich werde seine Grundlagen, die im Internet leicht zu finden sind, nicht beschreiben. Es sollte auch beachtet werden, dass der Artikel die Arbeit von mod_rewrite hervorhebt, wenn er seine Anweisungen in der .htaccess-Datei verwendet. Unterschiede im Arbeitskontext sind am Ende des Artikels angegeben.

Sie haben also mod_rewrite studiert, mehrere RewriteRules erstellt und endlose Weiterleitungen gefunden, mit dem Fall, dass die Regel Ihre Anfrage aus irgendeinem Grund nicht abfängt, und mit der unvorhersehbaren Arbeit der Regelgruppe, wenn die nachfolgende Regel die durch die vorherigen Regeln sorgfältig erstellte Abfrage unerwartet ändert.

Womit arbeitet RewriteRule?

Der ersten RewriteRule wird der Pfad von der Stelle, an der sich .htaccess befindet, an die angeforderte Datei übergeben. Diese Zeile beginnt niemals mit "/". Nachfolgende RewriteRule überträgt das Ergebnis früherer Transformationen.

Um zu verstehen, wie RewriteRule funktioniert, müssen Sie zuerst feststellen, mit was es arbeitet . Berücksichtigen Sie, wie Apache eine Zeichenfolge erhält, die zunächst zur Verarbeitung in .htaccess an RewriteRule übergeben wird.

Wenn du anfängst mit mod_rewrite zu arbeiten, ist es logisch anzunehmen, dass es mit Links funktioniert. Im Fall der Verwendung von mod_rewrite in .htaccess ist dies jedoch nicht der Fall. Tatsächlich übergibt RewriteRule den Link nicht, sondern den Pfad zur angeforderten Datei .

Aufgrund der internen Architektur von Apache in dem Moment, in dem .htaccess zum Einsatz kommt, kann mod_rewrite nur den Pfad zu der Datei verarbeiten, die verarbeitet werden muss. Dies liegt daran, dass die Anfrage vor der Übertragung an mod_rewrite bereits von anderen Modulen (zum Beispiel mod_alias) geändert werden konnte und der endgültige Pfad zur Datei auf der Site möglicherweise nicht mehr mit der ursprünglichen Verbindung übereinstimmt. Wenn mod_rewrite mit der Quellverknüpfung arbeitete, würde dies die Aktion der Module verletzen, die die Anforderung zuvor geändert hatten.

Daher wird in mod_rewrite ein absoluter Pfad an die Datei übergeben, die verarbeitet werden muss. Außerdem kennt mod_rewrite den Pfad zu .htaccess, in dem die Regeln von RewriteRule liegen. Um aus dem Pfad zu der Datei etwas Ähnliches wie den Link zu machen, mit dem der Entwickler der Site arbeiten will, schneidet mod_rewrite den absoluten Pfad zur .htaccess Datei ab.

Daher wird dieser Pfad, von dem der Pfad zu .htaccess abgeschnitten wird, an die erste RewriteRule übergeben. Zum Beispiel:

  • Anfrage: http://example.com/templates/silver/images/logo.gif
  • DocumentRoot: /var/www/beispiel.com
  • Pfad zur Datei: /var/www/example.com/templates/silver/images/logo.gif
  • .htaccess befindet sich unter: /var/www/example.com/templates/.htaccess
  • In der ersten RewriteRule wird übertragen: silver / images / logo.gif
  • Hinweis: "templates /" wurde ebenfalls abgeschnitten.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Der Pfad zu .htaccess ist mit dem Schrägstrich abgeschnitten. Daraus ergibt sich ein Effekt: Die Zeichenfolge, die anfänglich an die RewriteRule-Verarbeitung übergeben wird, beginnt nie mit "/".

Es ist wichtig, sich daran zu erinnern, was RewriteRule tut . Es verarbeitet nicht den Site-Namen, die Argumente, die an das Skript übergeben werden, und der Link behandelt nicht alle, wenn sich .htaccess nicht im Stammverzeichnis der Site befindet. All dies wird von RewriteCond erledigt, auf das kurz später eingegangen wird. Also:

# работать не будет - правило начинается со /
RewriteRule ^/index.php$ /my-index.php

# работать не будет - название сайта не анализируется RewriteRule
RewriteRule ^example.com/.* http://www.example.com

# работать не будет - аргументы ссылки не попадают в RewriteRule
RewriteRule index.php\?newspage=([0-9]+) news.php?page=$1
# работать не будет - правило начинается со /
RewriteRule ^/index.php$ /my-index.php

# работать не будет - название сайта не анализируется RewriteRule
RewriteRule ^example.com/.* http://www.example.com

# работать не будет - аргументы ссылки не попадают в RewriteRule
RewriteRule index.php\?newspage=([0-9]+) news.php?page=$1
# Будет работать только если .htaccess находится там же, где находится папка templates,
# например, в корне сайта. То есть, если .htaccess находится в templates/.htaccess , правило
# работать НЕ БУДЕТ, потому что mod_rewrite отрежет путь до .htaccess и на вход RewriteRule
# строка попадет уже без "templates/"
RewriteRule ^templates/common/yandex-money.gif$ templates/shared/yad.gif
# Будет работать только если .htaccess находится там же, где находится папка templates,
# например, в корне сайта. То есть, если .htaccess находится в templates/.htaccess , правило
# работать НЕ БУДЕТ, потому что mod_rewrite отрежет путь до .htaccess и на вход RewriteRule
# строка попадет уже без "templates/"
RewriteRule ^templates/common/yandex-money.gif$ templates/shared/yad.gif

Zu Beginn der Verwendung von mod_rewrite empfehle ich, nur in .htaccess im Stammverzeichnis der Site zu arbeiten. Dies wird die Kontrolle über seinen Betrieb etwas vereinfachen.

Mit was RewriteRule funktioniert, haben wir es herausgefunden. Mal sehen, wie es funktioniert .

Wie RewriteRule funktioniert

RewriteRule konvertiert einfach einen String nach regulären Ausdrücken, und das war's. RewriteRule arbeitet mit einer Zeichenfolge, nicht mit einer Verknüpfung oder einem Pfad zu der Datei.

Wie wir oben herausgefunden haben, stammt die Eingabe von RewriteRule aus dem Pfad von .htaccess zur angeforderten Datei. Es ist am besten, jetzt von Pfaden und Referenzen zu abstrahieren und zu überlegen, mit was RewriteRule als normale Linie arbeitet. Diese Zeile wird von RewriteRule an RewriteRule übergeben und geändert, wenn eines der RewriteRules funktioniert hat.

Im Allgemeinen, wenn Sie die Schwierigkeiten mit der Verwendung von Flags ausschließen (einige davon werden wir weiter unten diskutieren) und die Schwierigkeit reguläre Ausdrücke zu erstellen (auf die wir in diesem Artikel nicht eingehen werden), funktioniert RewriteRule SEHR einfach.

  1. Wir nahmen eine Linie.
  2. Verglichen mit dem regulären Ausdruck im ersten Argument.
  3. Wenn es eine Übereinstimmung gibt, ersetzen Sie die gesamte Zeichenfolge durch den Wert des zweiten Arguments.
  4. Sie haben die Zeile an die nächste RewriteRule übergeben.

Das ist im Allgemeinen alles. Um zu veranschaulichen, dass RewriteRule mit einer Zeichenfolge arbeitet, betrachten Sie das folgende fantastische Beispiel:

# Запрос: http://mysite.com/info.html
# В первый RewriteRule попадет "info.html"

# Преобразовываем запрос в произвольную строку.
RewriteRule ^info.html$ "I saw a turtle in the hole. And it was dancing rock-n-roll. And it was smiling. All in all, it was a very funny doll."

# "info.html" -> "I saw a turtle..."

# Заменяем эту строку на внешнюю ссылку.
RewriteRule turtle https://example.com/information/index.html

# "I saw a turtle..." -> "https://example.com/information/index.html"

# Заменяем имя сайта!
RewriteRule ^(.*)example.com(.*)$ $1example.org$2

# "https://example.com/information/index.html" -> "https://example.org/information/index.html"

# Заменяем протокол!
RewriteRule ^https :( .*)$ ftp:$1

# "https://example.org/information/index.html" -> "ftp://example.org/information/index.html"

# Заменяем конечную ссылку.
RewriteRule ^(.*)/index.html$ $1/main.php

# "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"

Wie Sie sehen, kümmert sich RewriteRule nicht darum, was zu tun ist - es konvertiert nur die Zeichenfolge gemäß den angegebenen Argumenten. Wenn Sie möchten, können Sie alle Daten-Arrays in der Zeile speichern, wenn Sie wollen, Ausdauer und gute Kenntnisse der regulären Ausdrücke, können Sie mindestens Tic-Tac-Toe auf RewriteRule schreiben.

Hier ist es notwendig, eine Notiz zu machen: Obwohl RewriteRule mit einer sauberen Zeichenfolge arbeitet, ist es immer noch so ausgerichtet, dass es mit Referenzen arbeitet. Daher wird es in besonderer Weise auf die Zeilen antworten, die mit "https: //" oder Analoga beginnen (denken Sie daran, dass wir eine externe Weiterleitung durchführen wollten) und das "?" (zählt die folgenden Zeichen als Argumente, die für die Abfrage ersetzt werden müssen). Aber jetzt interessiert es uns nicht - es ist wichtig zu verstehen, dass es in RewriteRule keine Magie gibt - es braucht nur eine Zeile und ändert es so, wie du es gesagt hast. Externe Redirects und Argumente, die wir später im Artikel betrachten werden, gibt es auch dort zu sprechen.

Nachdem alle Transformationen abgeschlossen sind und die letzte RewriteRule ausgeführt wurde, wird RewriteBase wirksam.

Wozu dient RewriteBase?

Wenn die resultierende Abfrage nach der Konvertierung relativ ist und sich vom Original unterscheidet, fügt sich RewriteBase auf der linken Seite hinzu. Sie müssen RewriteBase in .htaccess angeben. Sein Wert ist der Pfad vom Site-Root zu .htaccess. RewriteBase wird nur nach allen RewriteRules ausgeführt, nicht zwischen ihnen.

Wir haben bereits erwähnt, dass mod_rewrite, das in .htaccess arbeitet, den absoluten Pfad zur angeforderten Datei erhält. Um es an RewriteRule zu übergeben, schneidet mod_rewrite den Pfad zu .htaccess ab. Dann ändern die Regeln von RewriteRule nacheinander die Anfrage. Und nachdem die Anforderung geändert wurde, muss Apache den absoluten Pfad zu der Datei wiederherstellen, den sie schließlich verarbeiten muss. RewriteBase ist eigentlich ein Hack, der hilft, den Quellpfad zu einer Datei wiederherzustellen.

RewriteBase wird nach allen Transformationen ausgeführt. Dies bedeutet, dass die Anforderung zwischen RewriteRule nicht geändert wird und erst wirksam wird, wenn alle RewriteRules ausgeführt werden.

Nach allen Konvertierungen sieht RewriteBase aus, der relative Wert ist der endgültige oder absolute Pfad. Im Kontext von Apache meinen wir einen relativen oder absoluten Pfad, der von der Wurzel der Site ausgeht:

  • images / logo.gif - relativ.
  • /images/logo.gif - absolut (am Anfang des Schrägstrichs).
  • http://example.com/images/logo.gif - das absoluteste von allen.

Wenn der Pfad absolut ist, führt RewriteBase nichts aus. Und wenn relativ - RewriteBase hängt sich nach links. Dies funktioniert sowohl für interne als auch für externe Weiterleitungen:

# .htaccess находится в /images/
# RewriteBase указан /images/
RewriteBase /images/

# Запрос http://example.com/images/logo.gif
# На вход RewriteRule попадает "logo.gif"
RewriteRule ^logo.gif$ logo-orange.gif
# После RewriteRule: "logo.gif" -> "logo-orange.gif"
# После RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif"

# Запрос http://example.com/images/header.png
# На вход RewriteRule попадает "header.png"
RewriteRule ^header.png$ /templates/rebranding/header.png
# После RewriteRule: "header.png" -> "/templates/rebranding/header.png"
# После RewriteBase: ничего не меняется, так итоговый результат преобразований начинается со "/'.

# Запрос http://example.com/images/director.tiff
# На вход RewriteRule попадает "director.tiff"
# Используем внешний относительный редирект
RewriteRule ^director.tiff$ staff/manager/director.tiff [R=301]
# После RewriteRule: "director.tiff" -> "staff/manager/director.tiff"
# + mod_rewrite запомнил, что будет внешний редирект
# После RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/director.tiff"
# mod_rewrite вспомнил про внешний редирект:
# "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff

Üblicherweise entwickelt sich nach einiger Bekanntschaft mit mod_rewrite folgende Gewohnheit: 1) füge jedem .htaccess "RewriteBase /" hinzu, 2) alle Weiterleitungen beginnen mit einem Schrägstrich: "RewriteRule news.php /index.php?act=news". Dies hilft, die Artefakte von RewriteBase loszuwerden, aber es ist falsch, dies zu tun. Jetzt, wo wir wissen, was RewriteBase macht, können wir die folgenden korrekten Regeln formulieren:

  1. RewriteBase muss mit dem Pfad vom Site-Root zu .htaccess übereinstimmen.
  2. Sie müssen die Umleitung nur dann von "/" aus starten, wenn Sie einen absoluten Pfad vom Site-Stammverzeichnis zur Datei angeben müssen.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Was passiert, wenn ich RewriteBase nicht spezifiziere? Apache macht es standardmäßig gleich dem absoluten Pfad im Dateisystem vor .htaccess (zum Beispiel /var/www/example.com/templates/). Die Unkorrektheit einer solchen Annahme Apache manifestiert sich auf externe relative Weiterleitungen:

# Запрос http://example.com/index.php
# DocumentRoot: /var/www/example.com/
# .htaccess находится в корне сайта, и в нем НЕ УКАЗАН RewriteBase.
# Поэтому по умолчанию RewriteBase равен абсолютному пути до .htaccess: /var/www/example.com/

# На входе RewriteRule - "index.php"
RewriteRule ^index.php main.php [R]
# На выходе: "index.php" -> "main.php"
# mod_rewrite запомнил, что нужен внешний редирект

# Закончились RewriteRule
# mod_rewrite все равно выполняет RewriteBase, так как у него есть значение по умолчанию.
# Получается: "main.php" -> "/var/www/example.com/main.php"

# Здесь mod_rewrite вспоминает, что был внешний редирект:
# "/var/www/example.com/main.php" -> http://example.com/var/www/example.com/main.php

# Получилось совсем не то, что имели в виду.

Also ging die Anfrage durch alle RewriteRules, nach denen RewriteBase bei Bedarf hinzugefügt wurde. Sollte Apache nun die Datei angeben, zu der der resultierende Pfad führt? Nein. Jetzt wird die resultierende Abfrage erneut verarbeitet.

Wie funktioniert mod_rewrite? Flagge [L]

mod_rewrite startet die Abfrageverarbeitung immer wieder, bis sie aufhört, sich zu ändern. Und die [L] Flagge kann es nicht stoppen.

Beim Erstellen mehr oder weniger komplexer Konfigurationen von mod_rewrite ist es wichtig zu verstehen, dass das Ändern der Abfrage nicht mit der letzten RewriteRule endet . Nachdem die letzte Regel von RewriteRule funktioniert hat und RewriteBase hinzugefügt wurde, schaut mod_rewrite, ob sich die Anfrage geändert hat oder nicht. Wenn sich die Anforderung geändert hat, beginnt ihre Verarbeitung erneut am Anfang von .htaccess.

Apache macht dies, weil es während der Modifikation der Anfrage in ein anderes Verzeichnis umgeleitet werden könnte. Es kann sein eigenes .htaccess haben, das an der vorherigen Abfrageverarbeitung nicht teilnahm. In der gleichen neuen .htaccess-Regel kann es Regeln geben, die sich auf die Verarbeitung der Anfrage auswirken - sowohl die Regeln von mod_rewrite als auch die Regeln anderer Module. Um diese Situation ordnungsgemäß zu behandeln, muss Apache den gesamten Verarbeitungszyklus erneut ausführen.

- Warte, aber es gibt ein Flag [L] , das die Verarbeitung von mod_rewrite'om stoppt!

Nicht genau. Das Flag [L] stoppt die aktuelle Iteration der Anforderungsverarbeitung. Wenn die Anforderung jedoch von den RewriteRules geändert wurde, die noch funktionieren, startet Apache den Zyklus der erneuten Verarbeitung der Anforderung von der ersten RewriteRule.

# Запрос: http://example.com/a.html

RewriteBase /

RewriteRule ^a.html$ b.html [L]
RewriteRule ^b.html$ a.html [L]

Das obige Beispiel führt am Ende zu einer unendlichen Umleitungsschleife und zum "Internal Server Error". In diesem Beispiel ist eine Endlosschleife offensichtlich, aber bei komplexeren Konfigurationen kann es erforderlich sein, die Regeln zu untersuchen, um zu ermitteln, welche Anforderungen miteinander verknüpft sind.

Um solche Situationen zu vermeiden, wird empfohlen, das Kennzeichen [L] nur bei Bedarf zu verwenden. Notwendigkeit kann von zwei Arten sein:

  1. Wenn eine externe Umleitung verwendet wird - [L, R = 301] oder [L, R = 302]. Bei einer externen Weiterleitung ist eine Weiterverarbeitung der Anfrage unerwünscht (siehe unten zum Flag [R]), und es wird besser gestoppt
  2. In .htaccess gibt es eine Schleife, die nicht entsorgt werden kann, und die Anfrage für mod_rewrite sollte beendet werden. In diesem Fall wird eine spezielle Konstruktion verwendet - siehe Tipps zu diesem Thema am Ende des Artikels.

Aber das folgende Beispiel wird nicht hängen bleiben. Versuchen Sie herauszufinden, warum und welche Datei schließlich an Apache übergeben wird.

# Запрос: http://example.com/a.html
# Начало .htaccess

RewriteBase /
RewriteRule ^a.html$ b.html
RewriteRule ^b.html$ a.html

# Конец .htaccess

Wie funktioniert mod_rewrite? Die Flagge [R]

Das [R] -Flag hört nicht auf, die Anfrage zu verarbeiten und gibt sofort die externe Weiterleitung zurück. Stattdessen erinnert er sich an die Notwendigkeit einer externen Weiterleitung, und die Verarbeitung der Anforderung wird mit der folgenden RewriteRule fortgesetzt. Es wird empfohlen, immer das [L] -Flag zu verwenden.

Das [R] -Flag weist Apache an, dass es sich nicht um eine interne, sondern um eine externe Weiterleitung handelt, die ausgeführt werden muss. Was ist der Unterschied zwischen einer externen Weiterleitung und einer internen? Interne Umleitung ändert einfach den Pfad zu der Datei, die dem Benutzer gegeben wird, während der Benutzer denkt, dass er die Datei erhält, die er ursprünglich angefordert hat. Bei einer externen Weiterleitung gibt Apache anstelle des Inhalts der Datei den Status der Antwort 301 oder 302 zurück und meldet den Link, über den sich der Browser mit der Datei verbinden sollte.

Es scheint, dass Apache bei der Verarbeitung des [R] -Flags die RewriteRule-Verarbeitung sofort stoppen und die externe Weiterleitung an den Benutzer zurückgeben sollte. Aber erinnern wir uns an ein fantastisches Beispiel aus dem Abschnitt "Wie funktioniert RewriteRule?" Darin haben wir zuerst das [R] -Flag angegeben, was auf die Notwendigkeit einer externen Weiterleitung hinweist, und dann die Änderung der Verbindung mit der folgenden RewriteRule fortgesetzt.

So funktioniert Apache, wenn eine externe Weiterleitung angegeben wird. Es "markiert" sich einfach damit, dass, nachdem alle Regeln erfüllt sind, der Status 302 (standardmäßig) zurückgegeben werden muss, aber gleichzeitig alle RewriteRules weiter unten in der Liste ausgeführt werden. Wir können die Abfrage weiter modifizieren, so wie wir sie brauchen. Das Einzige, was nicht funktioniert, ist, die Weiterleitung intern zu machen.

Es ist jedoch unwahrscheinlich, dass Sie es in irgendeiner Weise ändern möchten, nachdem Sie die externe Weiterleitung aufgegeben haben. Daher wird empfohlen, wenn Sie das [R] -Flag verwenden , es zusammen mit [L] anzugeben :

# BlackJack переехал на красивое имя
RewriteRule ^bj/(.*) blackjack/$1 [R=301,L]

# Можно использовать просто внешнюю ссылку
RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]

Anstatt das Flag [R] zu verwenden, können Sie einfach eine externe Referenz angeben. In diesem Fall wird Apache erraten, dass eine externe Weiterleitung erforderlich ist. Wie bei der expliziten Angabe des Flags [R] wird hier empfohlen, das Flag [L] zu verwenden.

  • Wenn eine externe Weiterleitung zu derselben Site führt, ist es besser, das Flag [R] zu verwenden, ohne eine vollständige Referenz anzugeben (dh eine relative externe Weiterleitung zu verwenden). Dadurch wird die Regel unabhängig vom Site-Namen.
  • Wenn eine externe Weiterleitung zu einer anderen Website führt, andernfalls nicht als vollständige externe Verknüpfung, wird dies nicht funktionieren.

Wie funktioniert mod_rewrite? Angeben von Abfrageparametern und des [QSA] -Flags

Das Ändern der Abfrageparameter in RewriteRule ändert nicht die Zeichenfolge, mit der die nächste RewriteRule ausgeführt wird. Wenn Sie jedoch die Parameter ändern, wird die Variable% {QUERY_STRING} geändert, mit der RewriteCond arbeiten kann.

Verwendete Terminologie: "Parameter" - Abfrageparameter, "Argumente" - RewriteRule-Argumente.

Mit RewriteRule können Sie nicht nur den Pfad zu der Datei ändern, die verarbeitet werden soll, sondern auch die Parameter der GET-Anfrage, die an sie übergeben werden. Dies wird oft verwendet, um die NC-Verarbeitung an einen üblichen Skript-Handler zu übergeben, zum Beispiel:

RewriteBase /

# Запрос: http://example.com/news/2010/07/12/grand-opening.html
# На входе: "news/2010/07/12/grand-opening.html"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После RewriteRule: "news/2010/07/12/grand-opening.html" -> "index.php"
# %{QUERY_STRING}: "" -> "act=news&what=2010/07/12/grand-opening.html"

In dem Moment, in dem die RewriteRule-Regel ein Fragezeichen im zweiten Argument findet, erkennt sie, dass sich die Parameter in der Anfrage geändert haben. Infolgedessen tritt das folgende auf:

  1. RewriteRule ersetzt die Zeichenfolge, mit der es arbeitet, durch einen Teil des zweiten Arguments vor dem Fragezeichen . Beachten Sie, dass die neuen Abfrageparameter nicht in die Zeichenfolge fallen, mit der die nachfolgenden RewriteRule-Regeln arbeiten.
  2. Ein Teil des zweiten Arguments nach dem Fragezeichen fällt in die Variable% {QUERY_STRING}. Wenn das Flag [QSA] angegeben wurde, werden die Abfrageparameter an den Anfang von% {QUERY_STRING} angehängt. Wenn das Flag nicht angegeben wurde, wird% {QUERY_STRING} vollständig durch die Abfrageparameter aus der RewriteRule ersetzt.

Noch ein paar Beispiele:

RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/"

Höchstwahrscheinlich funktioniert die obige Regel nicht richtig, weil das Seitenargument verloren ist. Lasst uns das beheben:

RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1 [QSA]
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/&page=2"

Wir haben nur das Flag [QSA] hinzugefügt und die Regel hat richtig funktioniert.

Sie können verstehen, dass das Ändern der Abfrageparameter% {QUERY_STRING} ändert , was später in RewriteCond verwendet werden kann. Dies sollte bei der Erstellung der nachfolgenden Regeln, die die Argumente überprüfen, berücksichtigt werden.

- Natürlich ändert sich das, weil die Anfrage Apache'm neu bearbeitet!

Nein,% {QUERY_STRING} ändert sich sofort . Ich werde nicht den Beweis geben - über die Parameter und so schon mehr als interessant zu lesen geschrieben :)

Was kann ich tun, um in RewriteCond genau die Abfrageparameter einzuchecken, die der Benutzer übertragen hat, anstatt sie durch RewriteRules zu ändern? Siehe die Tipps am Ende des Artikels.

RewriteCond und Leistung

Zuerst wird die Abfrage mit RewriteRule abgeglichen, und nur dann wird die zusätzliche RewriteCond-Bedingung verwendet.

Ein paar Worte sollten über die Reihenfolge gesagt werden, in der mod_rewrite die Anweisungen ausführt. Da auf .htaccess zuerst RewriteCond und dann RewriteRule folgen, scheint es so zu sein, dass mod_rewrite zuerst alle Bedingungen prüft und dann RewriteRule ausführt.

In der Tat passiert alles anders herum. First mod_rewrite prüft, ob der aktuelle Wert der Anfrage mit dem regulären Ausdruck RewriteRule übereinstimmt, und prüft erst dann alle in RewriteCond aufgeführten Bedingungen.

Wenn Sie also einen regulären Ausdruck für zwei Seiten in RewriteRule haben und Sie, wenn Sie über die Leistung nachdenken, sich entschieden haben, die Ausführung dieser Regel auf zusätzlichen RewriteCond zu beschränken, wird nichts passieren. In diesem Fall ist es besser, die RewriteRule-Flags [C] oder [S] zu verwenden, um eine komplexere Regel zu überspringen, wenn einfachere Überprüfungen nicht funktionieren.

Variablen und Flags von RewriteCond, andere Flags von RewriteRule und andere

Lesen Sie die Dokumentation.

Wir haben uns mit den Prinzipien der Arbeit von RewriteRule, RewriteBase, flags [L], [R] und [QSA] vertraut gemacht und auch den Mechanismus der Bearbeitung von Anfragen in mod_rewrite zerlegt. Aus dem unberührten blieb: andere Flags von RewriteRule, Direktiven RewriteCond und RewriteMap.

Glücklicherweise enthalten diese Direktiven und Flags keine Rätsel und funktionieren genau so, wie in den meisten Lehrbüchern beschrieben. Für ihr Verständnis genügt es, die offizielle Dokumentation zu lesen. Zunächst empfehle ich, die Liste der Variablen zu studieren, die in RewriteCond überprüft werden können -% {QUERY_STING},% {THE_REQUEST},% {REMOTE_ADDR},% {HTTP_HOST},% {HTTP: Header} usw.)

Der Unterschied in der Arbeit von mod_rewrite im Kontext von .htaccess und im Kontext von VirtualHost

Im Zusammenhang mit mod_rewrite funktioniert genau das Gegenteil.

Wie ich zu Beginn des Artikels gesagt habe, betrifft alles, was oben beschrieben wurde, die Verwendung von mod_rewrite im Kontext von .htaccess. Wenn mod_rewrite in verwendet wird Es wird anders funktionieren:

  • In der In RewriteRule wird der gesamte Anfragepfad beginnend mit dem ersten Schrägstrich bis zum Anfang der GET-Parameter abgerufen: "http://example.com/some/news/category/post.html?comments_page=3" -> "/ news / category / post. html ". Diese Zeile beginnt immer mit /.
  • Das zweite Argument von RewriteRule muss ebenfalls mit / beginnen, andernfalls wird eine "Ungültige Anfrage" angezeigt.
  • RewriteBase macht keinen Sinn.
  • Passage von Regeln tritt nur einmal auf. Das [L] -Flag hört wirklich auf, alle Regeln zu verarbeiten, die in beschrieben sind , ohne nachfolgende Iterationen.

Tipps und Lösungen

Hier sind Tipps zusammengestellt, die im Laufe des Artikels mitgebracht werden können, aber aus Gründen der Kürze der Präsentation des Materials aus dem Haupttext ausgeschlossen wurden.

Reguläre Ausdrücke erstellen

Versuchen Sie, reguläre Ausdrücke zu erstellen, damit sie genau die Abfragen definieren, die Sie ändern möchten, damit die RewriteRule-Regeln nicht versehentlich für eine andere Abfrage funktionieren. Zum Beispiel:

# Начинайте все регулярные выражения с "^" (признак начала строки)
# и заканчивайте "$" (признак конца строки):
RewriteRule ^news.php$ index.php
# Даже если в этом нет необходимости - для универсальности и лучшего понимания конфигурации:
RewriteRule ^news/(.*)$ index.php

# Если под маску должны попадать только цифры - укажите это явно.
# Если какие-то цифры постоянны, укажите их явно.
# Если в оставшейся части запроса не могут присутствовать слеши, ограничьте их присутствие.
# Не забывайте экранировать "." (точки).
# Следующее правило нацелено на запросы вида http://example.com/news/2009/07/28/b-effect.html
RewriteRule ^news/20[0-9]{2}/[0-9]{2}/[0-9]{2}/[^/]+\.html index.php

Sie können jedoch über reguläre Ausdrücke auf unserer Website lesen:

Ändern externer Weiterleitungen

Trotz der Tatsache, dass mod_rewrite Ihnen erlaubt, sogar externe Weiterleitungen mit RewriteRule zu modifizieren, bis zum Protokoll, empfehle ich dringend, dies nicht zu tun. In dem Artikel wird ein Beispiel mit sich ändernden externen Weiterleitungen nur verwendet, um solche Konzepte wie "Links" und "Dateien" loszuwerden und deutlicher zu zeigen, dass RewriteRule mit einem einfachen String arbeitet.

Ich glaube nicht, dass die Entwickler von mod_rewrite davon ausgegangen sind, dass irgendjemand das tun würde, also sind alle möglichen Artefakte möglich. Tu es bitte nicht.

Wie man eine Endlosschleife stoppt

Manchmal ist die Umleitungslogik auf der Site so, dass mod_rewrite sie ohne besondere Aktionen als unendlichen Umleitungszyklus behandelt. Nehmen wir das folgende Beispiel.

Die Seite war /info.html. Ein SEO-Spezialist entschied, dass Suchmaschinen diese Seite besser indizieren würden, wenn sie /information.html genannt würden, und nach einer externen Weiterleitung mit info.html auf information.html gefragt hätten. Allerdings kann der Entwickler der Seite aus irgendeinem Grund nicht einfach info.html in information.html umbenennen und eine Umleitung vornehmen - er benötigt die zu liefernden Daten direkt aus der Datei info.html. Er schreibt folgende Regel:

# сделать внешний редирект
RewriteRule ^info.html information.html [R,L]
# но по запросу /information.html все равно отдать info.html
RewriteRule ^information.html info.html

... und trifft auf einen unendlichen Kreislauf. Jede Anfrage /information.html erhält erneut eine externe Weiterleitung auf /information.html.

Löse dieses Problem auf mindestens zwei Arten. Auf Habré wurde einer von ihnen bereits beschrieben - es ist notwendig, die Umgebungsvariable zu setzen und auf Grund ihres Wertes die Weiterleitungen zu stoppen. Der Code sieht so aus:

RewriteCond %{ENV:REDIRECT_FINISH} !^$
RewriteRule ^ - [L]

RewriteRule ^info.html$ information.html [R,L]
RewriteRule ^information.html$ info.html [E=FINISH:1]

Beachten Sie, dass mod_rewrite dem Variablennamen 'REDIRECT_' hinzufügt.

Die zweite Möglichkeit besteht darin, in THE_REQUEST nachzuschauen, was genau vom Benutzer angefordert wurde:

# Внешний редирект происходит только если пользователь запросил info.html.
# Если же info.html - это результат внутреннего перенаправления, правило срабатывать не будет.
RewriteCond %{THE_REQUEST} "^(GET|POST|HEAD) /info.html HTTP/[0-9.]+$"
RewriteRule ^info.html$ information.html [R,L]

RewriteRule ^information.html$ info.html

Analysieren der ursprünglichen Benutzeranforderung - Bekämpfen der Offenlegung von Apache-Links

Beim Verarbeiten der Anfrage erweitert Apache die codierten (URL-codierten) Zeichen von der ursprünglichen Anfrage. In einigen Fällen kann dies unerwünscht sein - der Entwickler möchte die ursprüngliche, nicht geänderte Benutzeranfrage genau prüfen. Sie können dies tun, indem Sie die Variable% {THE_REQUEST} in RewriteCond überprüfen:

RewriteCond %{THE_REQUEST} ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$
RewriteRule ^(.*)$ index.php?tag=%1 [L]

Empfohlene Dokumentation

Offizielle Apache-Dokumentation

Technische Details