Versteckte Funktionen von mod_rewrite

119

In mod_rewriteletzter Zeit scheint es eine anständige Anzahl von Threads zu geben, die ein wenig verwirrt darüber sind, wie bestimmte Aspekte davon funktionieren. Aus diesem Grund habe ich einige Hinweise zur allgemeinen Funktionalität und möglicherweise einige nervige Nuancen zusammengestellt.

Welche anderen Funktionen / häufigen Probleme sind Ihnen begegnet mod_rewrite?

Owen
quelle
5
Siehe auch serverfault.com/questions/214512/…
Michael Myers

Antworten:

203

Wo können mod_rewrite-Regeln platziert werden?

mod_rewriteRegeln können in der httpd.confDatei oder in der .htaccessDatei platziert werden. Wenn Sie Zugriff auf haben, httpd.confbietet das Platzieren von Regeln hier einen Leistungsvorteil (da die Regeln einmal verarbeitet werden, im Gegensatz zu jedem .htaccessAufruf der Datei).

Protokollierung von mod_rewrite-Anforderungen

Die Protokollierung kann innerhalb der httpd.confDatei (einschließlich <Virtual Host>) aktiviert werden :

# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2

Häufige Anwendungsfälle

  1. So leiten Sie alle Anfragen an einen einzigen 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 verwenden FallbackResource.

  2. 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]
    
  3. SSL erzwingen

    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://example.com/$1 [R,L]
    
  4. Gemeinsame Flaggen:

    • [R]oder [redirect]- eine Umleitung erzwingen (standardmäßig eine temporäre Umleitung 302)
    • [R=301]oder [redirect=301]- eine permanente 301-Umleitung erzwingen
    • [L]oder [last]- Beenden Sie den Umschreibvorgang (siehe Hinweis unten in den häufigsten Fallstricken).
    • [NC]oder [nocase]- Geben Sie an, dass beim Abgleichen die Groß- und Kleinschreibung nicht berücksichtigt werden soll


    Die Verwendung der Langform von Flags ist häufig besser lesbar und hilft anderen, die Ihren Code später lesen.

    Sie können mehrere Flags durch ein Komma trennen:

    RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
    

Häufige Fehler

  1. Mixing mod_aliasStyle Redirects mitmod_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 mischen mod_aliasmit mod_rewrite, aber es ist mehr Arbeit als nur grundlegende Umleitungen wie oben Handhabung.

  2. Der Kontext beeinflusst die Syntax

    In .htaccessDateien 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
    
  3. [L] ist nicht zuletzt! (manchmal)

    Das [L]Flag beendet die Verarbeitung weiterer Umschreiberegeln für diesen Durchlauf durch den Regelsatz . Wenn die URL in diesem Durchgang geändert wurde und Sie sich im .htaccessKontext oder im <Directory>Abschnitt befinden, wird Ihre geänderte Anforderung erneut über die URL-Analyse-Engine zurückgegeben. Und beim nächsten Durchgang kann es diesmal zu einer anderen Regel kommen. Wenn Sie dies nicht verstehen, sieht es oft so aus, als hätte Ihre [L]Flagge keine Wirkung.

    # processing does not stop here
    RewriteRule ^dirA$ /dirB [L] 
    # /dirC will be the final result
    RewriteRule ^dirB$ /dirC     
    

    Unser Umschreibungsprotokoll 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, besteht darin, das [END]Flag ( siehe Apache-Dokumente ) anstelle des [L]Flags zu verwenden, wenn Sie wirklich die weitere Verarbeitung von Regeln (und nachfolgenden Durchläufen) 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 haben, bleibt nur das [L]Flag hängen .

    Bei früheren Versionen müssen Sie sich auf RewriteCondAnweisungen verlassen, um zu verhindern, dass Regeln bei nachfolgenden Durchläufen der URL-Analyse-Engine übereinstimmen.

    # 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 (dh httpd.conf), der nicht dazu führt, dass Ihre Anforderung erneut analysiert wird.

Owen
quelle
10
Alter, total der beste Artikel im Internet jetzt auf Mod Rewrite. Ich hasse das Ding. Ich bin ein Lighttpd-Ketzer, weil ich mod_rewrite so sehr hasse.
Kent Fredric
3
Dies war die nützlichste Anleitung, die ich bisher auf mod_rewrite gefunden habe. Allein das Herausfinden von RewriteLog half, so viele Probleme zu beheben, dass das, was ich Tage brauchte, um es aufzuspüren, in ein paar Minuten umgewandelt wurde. (Ich meine, die Regeln wurden geschrieben, aber ich konnte nicht herausfinden, warum sie nicht funktionierten)
Joe Chin
1 Jahr alter Beitrag, aber eines der nützlicheren Dinge, die ich auf SO gefunden habe - für mich.
Erik
3
Das [L]Flag bedeutet, dass eine Regel in der aktuellen Verarbeitung die letzte ist. Dadurch wird das Umschreiben nicht beendet, da es sich um interne Weiterleitungen handelt. Sie dirBwenden sich also dirCbei der nächsten htaccess-Verarbeitung an. Alleine RewriteRule ^(.*)$ index.php?query=$1wird eine Endlosschleife interner Weiterleitungen sein (in der Praxis wird sie nach 10 Iterationen beendet). -1, weil Sie vorschlagen, dass [L] nicht das letzte ist . Der Umschreibvorgang wird nicht beendet, aber er ist der letzte .
Kbec
3
Ich glaube, dies RewriteCond %{HTTPS} offist die bevorzugte Methode, um nach einer HTTPS-Verbindung zu suchen (in Ihrem Beispiel, um Nicht-SSL-Verkehr zu HTTPS zu
erzwingen
22

Wenn Sie interne Weiterleitungen / Umschreibungen im .htaccess blockieren müssen, schauen Sie sich die an

RewriteCond %{ENV:REDIRECT_STATUS} ^$

Zustand, wie hier diskutiert .

Mromaine
quelle
Danke, das hat gerade mein Problem behoben!
Matthew
Danke auch für mich, Lebensretter!
Benjamin
Dies ist in der Tat ein Lebensretter! Die Leute sollten sich dessen bewusster sein. Tatsächlich werde ich dies jeder Frage .*mit der [L]Flagge vorschlagen, die ich gelesen habe, bevor ich hier ankam.
Qwerty
Ich habe mehrere Modifikationen gesehen 200, !=200, ^., ^$. Anscheinend wird die Variable 200für eine Umleitung auf gesetzt, aber auch auf anderen Seiten (Fehler und so) wird sie auf einen bestimmten Wert gesetzt. Nun das bedeutet , dass Sie entweder überprüfen , ob es is empty, is not empty, is 200oder is not 200, je nachdem , was Sie brauchen.
Qwerty
18

Der Deal mit RewriteBase:

Sie müssen fast immer RewriteBase einstellen. Wenn Sie dies nicht tun, vermutet Apache, dass Ihre Basis der Pfad der physischen Festplatte zu Ihrem Verzeichnis ist. Beginnen Sie also damit:

RewriteBase /
Sean McMillan
quelle
Ah. Das hat das Problem, das ich hatte, total behoben. Dank dafür!
Tom Savage
3
Irgendeine Art zu sagen RewriteBase .oder etwas, das darauf hinweist, dass die URL gleich bleiben soll, nur was Sie angegeben haben?
Jay K
Vielen Dank, dies war eine unbezahlbare Information. :)
AturSams
2
Sie müssen nur festlegen, RewriteBaseob Sie in der RewriteRuleDirektive die relative Pfadsubstitution verwenden. Es ist besser, relative Pfade zu vermeiden.
MrWhite
2
Ich bin mit dieser Antwort nicht einverstanden. In unserem RewriteBaseEntwicklerteam vermeiden wir dies insgesamt, da fast alle Entwickler falsch verstehen, was es tut. Wie @ w3d sagte, benötigen Sie es nur, wenn Sie Zeichen speichern und dieselbe Basis auf alle Ihre RewriteRules in einer Datei anwenden möchten. Ihr Code wird für andere wahrscheinlich klarer, wenn Sie ihn vermeiden.
Simon East
13

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 einer Datei zu erraten, nach der ich zu suchen glaube .

Ich erkläre: 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 erfasst werden. Überraschung! Diese Regel wird für die URL http: // myhost / file2 / somepath nicht berücksichtigt . Stattdessen werden Sie in file2.php aufgenommen.

Was los ist, ist, dass MultiViews automatisch erraten hat, dass die URL, die Sie tatsächlich wollten, http: //myhost/file2.php/somepath war und Sie gerne dorthin gebracht hat.

Jetzt haben Sie keine Ahnung, was gerade passiert ist, und stellen an diesem Punkt alles in Frage, 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 macht es.

Ok, kurz gesagt, wenn Sie möchten, dass mod_rewrite logisch funktioniert, ist das Deaktivieren von MultiViews ein Schritt in die richtige Richtung.

2- Aktivieren Sie FollowSymlinks

Options +FollowSymLinks 

Das hier, ich kenne die Details nicht wirklich, aber ich habe es schon oft erwähnt gesehen, also mach es einfach.

Michael Ekoka
quelle
Danke :) Ich habe unerwartete Überraschungen wie / log / activity bemerkt, die sich in /log.txt/activity verwandeln. Danke für den Tipp :) .. Schade, dass Computer niemals Spaß machen, wenn unerwartete Dinge passieren, wie versehentlich all deine Mitarbeiterinnen auf Facebook zu verführen :)
AturSams
1
+FollowSymLinkswird in der Dokumentation mod_rewriteaus vagen Sicherheitsgründen als obligatorisch für die Arbeit erwähnt.
Joey
Zwei Aussagen hier beunruhigen mich immens: "Ich bin nicht gut mit allen MultiViews-Funktionen vertraut, aber ich weiß, dass sie meine mod_rewrite-Regeln durcheinander bringen, wenn sie aktiv sind" und diese "Diese, ich kenne die Details nicht wirklich." , aber ich habe es schon oft erwähnt, also mach es einfach. ' Ich wünschte, Leute wie Sie würden auf SO keine Antworten über Dinge schreiben, bei denen Sie sich nicht sicher sind.
TheCarver
1
@PaparazzoKid: Ich denke, Sie verwechseln SO mit einer Enzyklopädie. Es ist eine Gemeinschaft von Menschen, die zusammenkommen, um ein Verständnis für die Technologie zu entwickeln, mit der sie arbeiten. Im Gegensatz zu AW White und Joey vor Ihnen ist Ihr Kommentar nahezu wertlos. MV und FSL sind zwei von vielen Optionen von Apache. Meine Antwort bezieht sich auf Fallstricke bei der Arbeit mit mod_rw, einem separaten Modul, das mit einigen Optionen in Konflikt steht und mit anderen funktioniert. Ich erklärte, wie MV mod_rw beeinflusst und erwähnte, dass + FSL eine beliebte Empfehlung ist. Joey bestätigte, dass es tatsächlich obligatorisch ist. Was bringst du auf den Tisch?
Michael Ekoka
Vielen Dank. Ich habe gerade den größten Teil einer Stunde damit verbracht, eine Legacy-Site zum Laufen zu bringen und zu versuchen, die Umschreiberegeln zu debuggen, nur um festzustellen, dass MultiViews alles außer Kraft setzte.
Andrew McCombe
5

Die 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, können Sie einen dynamischen Bereich des Worker-Servers hinzufügen.

RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
DrDol
quelle
4

Ein besseres Verständnis des [L] -Flag ist angebracht. Das [L] -Flag ist das letzte. Sie müssen nur verstehen, was dazu führt, dass Ihre Anfrage erneut durch die URL-Analyse-Engine geleitet wird. Aus den Dokumenten ( http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l ) (Hervorhebung von mir):

Das Flag [L] 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 , ist es wichtig zu verstehen, wie die Regeln verarbeitet werden. Die vereinfachte Form davon ist, dass nach der Verarbeitung der Regeln die umgeschriebene Anforderung an die URL-Analyse-Engine zurückgegeben wird, um zu tun, was sie will. Es ist möglich, dass bei der<Directory> Bearbeitungder umgeschriebenen Anforderung die .htaccess-Datei oder derAbschnitt.htaccesserneut angetroffen wird und der Regelsatz daher von Anfang an erneut ausgeführt wird. Am häufigsten geschieht dies, wenn eine der Regeln eine interne oder externe Umleitung verursacht und der Anforderungsprozess von vorne beginnt.

Das Flag [L] beendet also die Verarbeitung weiterer Umschreiberegeln für diesen Durchlauf durch den Regelsatz. Wenn Ihre mit [L] gekennzeichnete Regel die Anforderung geändert hat und Sie sich im .htaccess-Kontext oder im <Directory>Abschnitt befinden, wird Ihre geänderte Anforderung erneut über die URL-Analyse-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 Flag [L] anscheinend keine Auswirkung.

Der beste Weg, dies zu umgehen, besteht darin, das Flag [END] ( http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end ) anstelle des Flags [L] zu verwenden, wenn Sie wirklich aufhören möchten alle weitere Verarbeitung von Regeln (und anschließende Wiederholung). Das Flag [END] ist jedoch nur für Apache v2.3.9 + verfügbar. Wenn Sie also Version 2.2 oder niedriger haben, bleibt nur das Flag [L] hängen. In diesem Fall müssen Sie sich auf RewriteCond-Anweisungen verlassen, um zu verhindern, dass Regeln bei nachfolgenden Durchläufen der URL-Parsing-Engine übereinstimmen. Oder Sie müssen sicherstellen, dass sich Ihre RewriteRule in einem Kontext befinden (z. B. httpd.conf), der nicht dazu führt, dass Ihre Anforderung erneut analysiert wird.

JaredC
quelle
3

Ein weiteres großartiges Feature sind Rewrite-Map-Erweiterungen. Sie sind besonders nützlich, wenn Sie eine große Anzahl von Hosts / Umschreibungen zu handhaben haben:

Sie sind wie ein Schlüssel-Wert-Ersatz:

RewriteMap examplemap txt:/path/to/file/map.txt

Dann können Sie eine Zuordnung in Ihren Regeln 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

SEIN
quelle
Ignorieren Sie diese Funktion, wenn Sie .htaccess-basierte Umschreibungen verwenden. In diesem Zusammenhang funktioniert es nicht.
TerryE
2
Die RewriteMap-Direktive muss im Serverkontext (httpd.conf) verwendet werden. Sobald sie dort definiert ist, können Sie die Map über die RewriteRule in einer .htaccess-Datei verwenden.
JaredC
2

mod_rewrite kann Aspekte der Anforderungsbearbeitung ändern, ohne die URL zu ändern, z. B. das Setzen von Umgebungsvariablen, das Setzen von Cookies usw. Dies ist unglaublich nützlich.

Bedingt eine Umgebungsvariable festlegen:

RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC]
RewriteRule .* - [E=MY_ENV_VAR:%b]

Rückgabe einer 503-Antwort: RewriteRuleDas [R]Flag kann einen Nicht-3xx-Wert annehmen und eine nicht umleitende Antwort zurückgeben, z. B. für verwaltete Ausfallzeiten / Wartungsarbeiten:

RewriteRule .* - [R=503,L]

gibt eine 503-Antwort zurück (keine Umleitung an sich).

Außerdem kann mod_rewrite wie eine leistungsstarke Schnittstelle zu mod_proxy fungieren. Sie können dies also tun, anstatt ProxyPassAnweisungen zu schreiben :

RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]

Meinung: Die Verwendung von RewriteRules und RewriteConds zum Weiterleiten von Anforderungen an verschiedene Anwendungen oder Load Balancer basierend auf praktisch jedem denkbaren Aspekt der Anforderung ist einfach immens leistungsfähig. Durch die Steuerung von Anforderungen auf dem Weg zum Backend und die Möglichkeit, die Antworten auf dem Weg zurück 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! :) :)

wöchentlich
quelle