In letzter Zeit scheint es eine anständige Anzahl von mod_rewrite
- Threads zu geben, die ein wenig verwirrt darüber sind, wie bestimmte Aspekte davon funktionieren. Als Ergebnis habe ich ein paar Hinweise zur allgemeinen Funktionalität und vielleicht ein paar nervige Nuancen zusammengestellt.
Auf welche anderen Funktionen/häufigen Probleme sind Sie mit mod_rewrite
Gestoßen?
mod_rewrite
- Regeln können in die httpd.conf
- Datei oder in die .htaccess
- Datei eingefügt werden. Wenn Sie Zugriff auf httpd.conf
haben, bietet das Platzieren von Regeln hier einen Leistungsvorteil (da die Regeln einmal verarbeitet werden und nicht jedes Mal, wenn die Datei .htaccess
aufgerufen wird).
Die Protokollierung kann in der Datei httpd.conf
Aktiviert werden (einschließlich <Virtual Host>
):
# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2
So leiten Sie alle Anforderungen an einen einzelnen Punkt weiter:
RewriteEngine on
# ignore existing files
RewriteCond %{REQUEST_FILENAME} !-f
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} !-d
# map requests to index.php and append as a query string
RewriteRule ^(.*)$ index.php?query=$1
Seit Apache 2.2.16 können Sie auch FallbackResource
verwenden.
Umgang mit 301/302 Weiterleitungen:
RewriteEngine on
# 302 Temporary Redirect (302 is the default, but can be specified for clarity)
RewriteRule ^oldpage\.html$ /newpage.html [R=302]
# 301 Permanent Redirect
RewriteRule ^oldpage2\.html$ /newpage.html [R=301]
Hinweis: Externe Weiterleitungen sind implizit 302 Weiterleitungen:
# this rule:
RewriteRule ^somepage\.html$ http://google.com
# is equivalent to:
RewriteRule ^somepage\.html$ http://google.com [R]
# and:
RewriteRule ^somepage\.html$ http://google.com [R=302]
SSL erzwingen
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R,L]
Gemeinsame Flaggen:
[R]
Oder [redirect]
- erzwingen Sie eine Umleitung (standardmäßig 302 temporäre Umleitung)[R=301]
Oder [redirect=301]
- erzwingen Sie eine permanente 301-Umleitung[L]
Oder [last]
- Beenden Sie den Umschreibevorgang (siehe Hinweis unten in allgemeinen Fallstricken).[NC]
Oder [nocase]
- Geben Sie an, dass bei der Übereinstimmung die Groß- und Kleinschreibung nicht beachtet werden soll
Die Verwendung der Langform von Flags ist häufig besser lesbar und hilft anderen, die später Ihren Code lesen.
Sie können mehrere Flags mit einem Komma trennen:
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
Mischen von mod_alias
- Stilumleitungen mit mod_rewrite
# Bad
Redirect 302 /somepage.html http://example.com/otherpage.html
RewriteEngine on
RewriteRule ^(.*)$ index.php?query=$1
# Good (use mod_rewrite for both)
RewriteEngine on
# 302 redirect and stop processing
RewriteRule ^somepage.html$ /otherpage.html [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# handle other redirects
RewriteRule ^(.*)$ index.php?query=$1
Hinweis: Sie können mod_alias
Mit mod_rewrite
Mischen, dies erfordert jedoch mehr Arbeit als nur die oben beschriebenen grundlegenden Weiterleitungen.
Der Kontext beeinflusst die Syntax
In .htaccess
- Dateien wird im RewriteRule-Muster kein führender Schrägstrich verwendet:
# given: GET /directory/file.html
# .htaccess
# result: /newdirectory/file.html
RewriteRule ^directory(.*)$ /newdirectory$1
# .htaccess
# result: no match!
RewriteRule ^/directory(.*)$ /newdirectory$1
# httpd.conf
# result: /newdirectory/file.html
RewriteRule ^/directory(.*)$ /newdirectory$1
# Putting a "?" after the slash will allow it to work in both contexts:
RewriteRule ^/?directory(.*)$ /newdirectory$1
[L] ist nicht zuletzt! (manchmal)
Das Flag [L]
Beendet die Verarbeitung weiterer Umschreiberegeln für diesen Durchlauf durch den Regelsatz. Wenn jedoch die URL in diesem Durchgang geändert wurde und Sie sich im Kontext .htaccess
Oder im Abschnitt <Directory>
Befinden, wird Ihre geänderte Anforderung erneut durch die URL-Parsing-Engine zurückgeleitet. Und beim nächsten Durchgang kann es diesmal zu einer anderen Regel kommen. Wenn du das nicht verstehst, sieht es oft so aus, als hätte dein [L]
- Flag keine Wirkung gehabt.
# processing does not stop here
RewriteRule ^dirA$ /dirB [L]
# /dirC will be the final result
RewriteRule ^dirB$ /dirC
Unser Umschreibeprotokoll zeigt, dass die Regeln zweimal ausgeführt und die URL zweimal aktualisiert werden:
rewrite 'dirA' -> '/dirB'
internal redirect with /dirB [INTERNAL REDIRECT]
rewrite 'dirB' -> '/dirC'
Der beste Weg, dies zu umgehen, ist die Verwendung des Flags [END]
( siehe Apache-Dokumentation ) anstelle des Flags [L]
, Wenn Sie die weitere Verarbeitung von Regeln wirklich stoppen möchten (und nachfolgende Durchläufe). Das Flag [END]
Ist jedoch nur für Apache v2.3.9 + verfügbar. Ich bleibe nur bei der [L]
- Markierung.
In früheren Versionen müssen Sie sich auf RewriteCond
-Anweisungen verlassen, um den Abgleich von Regeln bei nachfolgenden Durchläufen des URL-Parsing-Moduls zu verhindern.
# Only process the following RewriteRule if on the first pass
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ...
Oder Sie müssen sicherstellen, dass sich Ihre RewriteRule in einem Kontext befinden (d. H. httpd.conf
), Durch den Ihre Anforderung nicht erneut analysiert wird.
wenn Sie interne Weiterleitungen/Umschreibungen in der .htaccess-Datei blockieren müssen, sehen Sie sich die .htaccess-Datei an
RewriteCond %{ENV:REDIRECT_STATUS} ^$
bedingung, wie hier besprochen .
Der Deal mit RewriteBase:
Sie müssen fast immer RewriteBase einstellen. Andernfalls vermutet Apache, dass Ihre Basis der Pfad der physischen Festplatte zu Ihrem Verzeichnis ist. Also fang damit an:
RewriteBase /
Andere Fallstricke:
1- Manchmal ist es eine gute Idee, MultiViews zu deaktivieren
Options -MultiViews
Ich bin nicht mit allen MultiViews-Funktionen vertraut, aber ich weiß, dass es meine mod_rewrite-Regeln durcheinander bringt, wenn es aktiv ist, weil eine seiner Eigenschaften darin besteht, zu versuchen, eine Erweiterung für eine Datei zu erraten, nach der ich zu suchen glaube .
Ich werde erklären: Angenommen, Sie haben 2 PHP-Dateien in Ihrem Webverzeichnis, file1.php und file2.php, und Sie fügen diese Bedingungen und Regeln zu Ihrem .htaccess hinzu:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ file1.php/$1
Sie gehen davon aus, dass alle URLs, die nicht mit einer Datei oder einem Verzeichnis übereinstimmen, von file1.php abgerufen werden. Überraschung! Diese Regel wird für die URL http: // myhost/file2/somepath nicht berücksichtigt. Stattdessen werden Sie in die Datei file2.php aufgenommen.
Was ist los ist, dass MultiViews automatisch erraten hat, dass die URL, die Sie eigentlich wollten, http: //myhost/file2.php/somepath war und Sie gerne dorthin gebracht hat.
Jetzt haben Sie keine Ahnung, was gerade passiert ist, und Sie hinterfragen jetzt alles, was Sie über mod_rewrite zu wissen glaubten. Sie fangen dann an, mit Regeln herumzuspielen, um zu versuchen, die Logik hinter dieser neuen Situation zu verstehen, aber je mehr Sie testen, desto weniger Sinn ergibt es.
Ok, kurz gesagt, wenn Sie möchten, dass mod_rewrite logisch funktioniert, ist das Ausschalten von MultiViews ein Schritt in die richtige Richtung.
2- Aktivieren Sie FollowSymlinks
Options +FollowSymLinks
Das hier kenne ich nicht wirklich, aber ich habe es schon oft erwähnt, also mach es einfach.
Gleichung kann mit folgendem Beispiel durchgeführt werden:
RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC]
# %1 is the string that was found above
# %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;"
#RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*)
# <> is used as an string separator/indicator, can be replaced by any other character
RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC]
RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]
Dynamischer Lastausgleich:
Wenn Sie den mod_proxy verwenden, um Ihr System auszugleichen, ist es möglich, einen dynamischen Bereich von Arbeitsservern hinzuzufügen.
RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
Ein besseres Verständnis der [L] -Flagge ist angebracht. Das [L] -Flag ist . Sie müssen nur verstehen, warum Ihre Anfrage erneut durch die URL-Parsing-Engine geleitet wird. Aus den Dokumenten ( http://httpd.Apache.org/docs/2.2/rewrite/flags.html#flag_l ) (Hervorhebung meiner):
Das [L] -Flag bewirkt, dass mod_rewrite die Verarbeitung des Regelsatzes beendet. In den meisten Kontexten bedeutet dies, dass bei Übereinstimmung der Regel keine weiteren Regeln verarbeitet werden. Dies entspricht dem letzten Befehl in Perl oder dem Befehl break in C. Verwenden Sie dieses Flag, um anzugeben, dass die aktuelle Regel sofort angewendet werden soll, ohne weitere Regeln zu berücksichtigen.
Wenn Sie RewriteRule entweder in .htaccess-Dateien oder in
<Directory>
- Abschnitten verwenden , Es ist wichtig zu verstehen, wie die Regeln verarbeitet werden. Die vereinfachte Form ist, dass nach der Verarbeitung der Regeln die umgeschriebene Anfrage zurückgegeben wird an die URL-Parsing-Engine, um das zu tun, was es damit tun mag. Es ist möglich, dass die .htaccess-Datei oder der Abschnitt<Directory>
Erneut angetroffen werden, wenn die umgeschriebene Anforderung verarbeitet wird, und der Regelsatz daher möglicherweise von Anfang an erneut ausgeführt wird. In den meisten Fällen tritt dies auf, wenn eine der Regeln eine interne oder externe Umleitung verursacht und der Anforderungsprozess erneut gestartet wird.
Das [L] -Flag beendet also die Verarbeitung weiterer Umschreibregeln für , die den Regelsatz durchlaufen. Wenn Ihre mit [L] markierte Regel die Anforderung jedoch geändert hat und Sie sich im .htaccess-Kontext oder im Abschnitt <Directory>
Befinden, wird Ihre geänderte Anforderung erneut über die URL-Parsing-Engine zurückgegeben. Und beim nächsten Durchgang kann es diesmal zu einer anderen Regel kommen. Wenn Sie nicht verstehen, was passiert ist, hat Ihre erste Umschreiberegel mit dem [L] -Flag anscheinend keine Wirkung.
Der beste Weg, dies zu umgehen, ist die Verwendung des Flags [END] ( http://httpd.Apache.org/docs/current/rewrite/flags.html#flag_end ) anstelle des Flags [L] , wenn Sie die weitere Verarbeitung von Regeln (und das anschließende erneute Parsen) wirklich stoppen möchten. Das [END] -Flag ist jedoch nur für Apache v2.3.9 + verfügbar. Wenn Sie also Version 2.2 oder niedriger verwenden, bleibt nur das [L] -Flag erhalten. In diesem Fall müssen Sie sich auf RewriteCond-Anweisungen verlassen, um den Abgleich von Regeln bei nachfolgenden Durchläufen des URL-Parsing-Moduls zu verhindern. Oder Sie müssen sicherstellen, dass sich Ihre RewriteRule in einem Kontext befinden (d. H. Httpd.conf), durch den Ihre Anforderung nicht erneut analysiert wird.
Ein weiteres großartiges Feature sind Rewrite-Map-Erweiterungen. Sie sind besonders nützlich, wenn Sie eine Vielzahl von Hosts/Rewrites zu bewältigen haben:
Sie sind wie ein Schlüssel-Wert-Ersatz:
RewriteMap examplemap txt:/path/to/file/map.txt
Dann können Sie in Ihren Regeln ein Mapping verwenden wie:
RewriteRule ^/ex/(.*) ${examplemap:$1}
Weitere Informationen zu diesem Thema finden Sie hier:
http://httpd.Apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc
mod_rewrite kann Aspekte der Anforderungsbearbeitung modifizieren, ohne die URL zu ändern, z. Setzen von Umgebungsvariablen, Setzen von Cookies usw. Dies ist unglaublich nützlich.
Bedingtes Setzen einer Umgebungsvariablen:
RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC]
RewriteRule .* - [E=MY_ENV_VAR:%b]
Rückgabe einer 503-Antwort: RewriteRule
's [R]
Flag kann einen Nicht-3xx-Wert annehmen und eine Nicht-Umleitungsantwort zurückgeben, z. für verwaltete Ausfallzeiten/Wartung:
RewriteRule .* - [R=503,L]
gibt eine 503-Antwort zurück (keine Weiterleitung per se).
Außerdem kann mod_rewrite wie eine leistungsstarke Schnittstelle für mod_proxy fungieren, sodass Sie dies tun können, anstatt ProxyPass
Direktiven zu schreiben:
RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
Meinung: Die Verwendung von RewriteRule
s und RewriteCond
s zum Weiterleiten von Anforderungen an verschiedene Anwendungen oder Lastausgleichsmodule, basierend auf praktisch jedem denkbaren Aspekt der Anforderung, ist einfach immens leistungsstark. Durch die Kontrolle der Anfragen auf dem Weg zum Backend und die Möglichkeit, die Antworten auf dem Rückweg zu ändern, ist mod_rewrite der ideale Ort, um alle routingbezogenen Konfigurationen zu zentralisieren.
Nehmen Sie sich Zeit, um es zu lernen, es lohnt sich! :)