it-swarm.com.de

Versteckte Funktionen von mod_rewrite

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?

119
Owen

Wo sollen mod_rewrite-Regeln platziert werden?

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).

Protokollierung von mod_rewrite-Anfragen

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

Häufige Anwendungsfälle

  1. 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.

  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] - 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]
    

Häufige Fehler

  1. 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.

  2. 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
    
  3. [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.

203
Owen

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 .

21
mromaine

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 /
18
Sean McMillan

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.

13
Michael Ekoka

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]
5
DrDol

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.

4
JaredC

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

3
B.E.

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 RewriteRules und RewriteConds 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! :)

2
cweekly