Software

RedirectMatch 301 in der .htaccess

· 4 Min. Lesezeit

RedirectMatch gehört zu mod_alias, nicht zu mod_rewrite. Das klingt nach Detailwissen, erklärt aber die meisten Fälle, in denen eine scheinbar korrekte Weiterleitung in der .htaccess einfach nicht greift.

Die Syntax ist überschaubar:

``apache RedirectMatch 301 ^/altes-verzeichnis/(.*)$ /neues-verzeichnis/$1 ``

Drei Teile: Statuscode, regulärer Ausdruck, Ziel. Der Ausdruck wird gegen den URL-Pfad geprüft, der Rückverweis $1 setzt ein, was die erste Klammer eingefangen hat.

Redirect, RedirectMatch, RewriteRule#

Redirect arbeitet mit einem Präfix. Es vergleicht den Anfang des Pfades und hängt den Rest unverändert an das Ziel an:

``apache Redirect 301 /alt/ /neu/ ``

Damit landet /alt/seite/ automatisch auf /neu/seite/. Für ganze Verzeichnisse ist das die einfachere und robustere Wahl. Kein regulärer Ausdruck, keine Anker, kein $1.

RedirectMatch ersetzt das Präfix durch einen regulären Ausdruck. Das braucht man, sobald ein Muster im Spiel ist: Dateiendungen, Ziffernfolgen, ein Segment mitten im Pfad.

RewriteRule aus mod_rewrite kann all das auch, plus Bedingungen über RewriteCond — Hostname, Abfragezeichenfolge, Kopfzeilen, Dateisystemtests. Diese Zusatzprüfungen sind der eigentliche Grund, mod_rewrite zu nehmen. Für eine reine Pfad-auf-Pfad-Weiterleitung ohne Bedingung ist RedirectMatch die kürzere und besser lesbare Zeile.

Der wichtigste Unterschied ist unsichtbar: Es sind zwei verschiedene Module. Beide werten ihre Regeln unabhängig voneinander aus, und die Reihenfolge in der Datei sagt nichts darüber, welches zuerst zum Zug kommt. Wer für dieselbe Adresse eine RedirectMatch-Zeile und eine RewriteRule schreibt, bekommt ein Ergebnis, das sich aus dem Dateiaufbau nicht ableiten lässt. Man sollte sich pro Adresse für ein Modul entscheiden.

Ein zweiter Unterschied fällt in Unterverzeichnissen auf: mod_alias prüft immer den vollständigen URL-Pfad ab der Wurzel. RewriteRule in einer .htaccess sieht den Pfad dagegen ohne das Verzeichnispräfix. Deshalb beginnen mod_alias-Muster mit ^/, mod_rewrite-Muster nicht.

Reguläre Ausdrücke und Rückverweise#

Die Klammern fangen ein, $1 bis $9 setzen wieder ein. Zwei typische Muster:

``apache RedirectMatch 301 ^/blog/([0-9]{4})/([0-9]{2})/(.+)$ /artikel/$3 RedirectMatch 301 ^/produkte/(.+)\.html$ /shop/$1/ ``

Die erste Zeile wirft Jahres- und Monatsangaben aus alten Beitragsadressen weg und behält nur den Titelteil. Die zweite entfernt eine Dateiendung und ergänzt einen Schrägstrich.

Zwei Feinheiten, die regelmäßig übersehen werden:

Der Punkt ist ein Sonderzeichen. In \.html muss er maskiert werden. Unmaskiert passt er auf jedes beliebige Zeichen, was das Muster stillschweigend zu weit macht.

Die Abfragezeichenfolge ist nicht Teil des Pfades. ?id=5 erscheint im Muster nicht und wird an das Ziel automatisch angehängt. Wer die Parameter loswerden will, setzt ein ? an das Ende des Ziels. Wer nach Parametern unterscheiden will, braucht mod_rewrite mit RewriteCond %{QUERY_STRING} — mod_alias kann das nicht.

Neben 301 sind auch andere Codes möglich. RedirectMatch 410 ^/eingestellt/ markiert Inhalte als endgültig entfernt und braucht kein Ziel.

Die vier Fehler, die dabei passieren#

1. Fehlende Anker. Ohne ^ und $ passt das Muster irgendwo im Pfad. RedirectMatch 301 /shop /laden trifft auch /archiv/shop-news/. Jedes Muster gehört verankert, sofern man nicht ausdrücklich einen Teiltreffer will.

2. Endlosschleife. Passt das Ziel wieder auf das eigene Muster, leitet der Server im Kreis, bis der Browser abbricht. Der Klassiker:

``apache RedirectMatch 301 ^/blog /blog/neu ``

/blog/neu beginnt selbst mit /blog und wird sofort erneut umgeleitet. Ein präziseres Muster mit Ankern und Klammern löst das: ^/blog/?$.

3. Reihenfolge. Innerhalb von mod_alias greift die erste passende Zeile, danach ist Schluss. Ein breites Muster ganz oben verschluckt alle spezifischen Regeln darunter. Spezifisches gehört nach oben, Allgemeines nach unten.

4. Ketten. Zwei aufeinanderfolgende Umzüge, zwei Regeln, und alte Adressen laufen erst auf die Zwischenstation und dann auf das Ziel. Jede Kette kostet eine zusätzliche Rundreise und geht bei jeder weiteren Umstellung ein Glied länger. Besser ist, die alten Regeln jeweils auf das aktuelle Ziel zu aktualisieren.

Dazu kommt eine Voraussetzung, die nichts mit der Syntax zu tun hat: In der .htaccess funktionieren mod_alias-Anweisungen nur, wenn der Server AllowOverride FileInfo erlaubt. Ist das nicht der Fall, quittiert Apache die Zeile mit einem 500er.

Prüfen, bevor der Cache es festschreibt#

Eine 301 wird von Browsern dauerhaft gespeichert. Ein Fehler ist deshalb im eigenen Browser kaum noch zu sehen, selbst nachdem er behoben ist. Es lohnt sich, zuerst mit 302 zu testen und erst nach bestandener Prüfung auf 301 umzustellen.

Geprüft wird ohne Browser:

``bash curl -sI https://beispiel.de/altes-verzeichnis/seite.html curl -sIL https://beispiel.de/altes-verzeichnis/seite.html | grep -E '^(HTTP|location)' ``

Der erste Aufruf zeigt Statuszeile und Location. Der zweite folgt der Weiterleitung und macht jede Zwischenstation sichtbar — genau die Kette, die man nicht haben will. Erwartet wird: ein 301, danach ein 200, dazwischen nichts.

Wo eine Weiterleitung ins Leere zeigt, entsteht dieselbe Sackgasse wie bei einem falschen Verweis; tote Links finden beschreibt das Aufspüren über den ganzen Auftritt. Und wenn ohnehin in der Datei gearbeitet wird, hilft der Überblick über die Standard-.htaccess von WordPress beim Trennen von eigenen und fremden Zeilen.