MrSnoot: Komisches Verhalten von RewriteRule

Hio,

ich habe bspw. folgende RewriteRule:

(#1): RewriteRule ^([^/\.]*)/$ hl.php?bereich=$1

um über '/grundlagen' auf /hl.php?bereich=grundlagen zuzugreifen.

Das klappt, '/grundlagen' wird in der Adresszeile allerdings automatisch zu '/grundlagen/'.

Anders sieht es bei einem zusätzlichen Unterverzeichnis aus:

(#2): RewriteRule ^([^/\.]*)/([^/\.]*)$ hl.php?bereich=$1&thema=$2

Zu beachten ist, dass hier am Ende des Suchstrings kein '/' steht. Bei der Eingabe von '/grundlagen/atombau' kommt auch diese Seite.

Wenn ich bei nur einer Variable (#1) den '/' am Ende des Suchstrings weglasse, wird die Seite nicht gefunden.
Wenn ich bei zwei Variablen (#2) den '/' am Ende des Suchstrings hinzufüge, muss ich explizit die Adresse auch mit '/' am Ende aufrufen.

Wieso kann ich bei (#1) den '/' am Ende also nicht weglassen, die Seite wird aber sowohl bei '/grundlagen' als auch '/grundlagen/' gefunden, bei (#2) muss ich jedoch die URL genau so mit oder ohne '/' eingeben, wie ich es in der Rule definiert habe?

  1. echo $begrüßung;

    ich habe bspw. folgende RewriteRule:

    (#1): RewriteRule ^([^/\.]*)/$ hl.php?bereich=$1

    um über '/grundlagen' auf /hl.php?bereich=grundlagen zuzugreifen.

    Das klappt, '/grundlagen' wird in der Adresszeile allerdings automatisch zu '/grundlagen/'.

    Das ist ein übliches Verhalten der Webserver. Die Ressource heißt /grundlagen/ mit / am Ende, da es ein Verzeichnis und keine Datei ist. Wenn der Server beim Request nach /foo keine Datei aber ein Verzeichnis foo findet, sendet er einen Redirect auf /foo/ zum Client. Das muss so sein, damit der Client relativ verlinkte Dokumente finden kann. Hieße die Ressource /foo ergäbe ein Link auf bar einen Request nach /bar. Bei /foo/ wird jedoch /foo/bar nachgefragt.

    Dein Request nach /grundlagen passt nicht auf die Regel. Es muss aber ein Verzeichnis namens grundlagen geben, sonst ergäbe es einen 404. Der Server schickt den Redirect, woraufhin der Client nach /grundlagen/ fragt und die Regel zutrifft.

    Den Rest der Fragen, so hoffe ich, kannst du nun selbst klären. Hilfreiche Werkzeuge sind die livehttpheaders-Extension für den Firefox, um sich den HTTP-Header-Verkehr zwischen Client und Server anzusehen, sowie das RewriteLog des Apachen, bei Unklarheiten des mod_rewrite-Verhaltens. Um Letzeres zu aktivieren braucht man aber administrativen Zugriff auf den Apachen.

    echo "$verabschiedung $name";

    1. Vielen Dank für die ausführliche Erklärung, das klingt plausibel :)

    2. Jetzt muss ich doch noch einmal nachhaken, da wieder etwas merkwürdiges (oder doch erklärliches? :D) passiert.

      Ich habe also diese Regel:

      RewriteRule ^([^/.]*)/$ hl.php?bereich=$1
      RewriteRule ^([^/.]*)/([^/.]*)/$ hl.php?bereich=$1&thema=$2

      Wenn ich als Adresse 'grundlagen/atombau' eingebe, wird also zu 'grundlagen/atombau/' umgeleitet, passt also. Ebenso klappt das mit jeder anderen Adresse, bis auf eine. Dort wird eben der '/' am Ende nicht automatisch ergänzt und die Seite nicht gefunden.

      Habe es mit Opera/FF/IE probiert um zu verhindern, dass irgendwas altes aus dem Cache kommt.

      Mit der FF-Extension seh ich leider nichts, was mir da weiterhelfen könnte.

      Irgendwas kleines muss ich da übersehen, aber was?

      1. Wenn ich als Adresse 'grundlagen/atombau' eingebe, wird also zu 'grundlagen/atombau/' umgeleitet

        Existiert denn der Ordner grundlagen/atombau/ physisch auf dem Server, oder ist das ein „virtueller Pfad“? Wenn er nicht existiert, würde ich nicht „passt also“ sagen – dann liegt nämlich irgendwo anders eine Fehlfunktion vor.

        Punkte innerhalb von Zeichenklassen bzw. negierten Zeichenklassen [^/.]  müssen nicht escaped werden, nur außerhalb, da die dort sonst eine andere Bedeutung (beliebiges Zeichen) haben.

  2. (#1): RewriteRule ^([^/\.]*)/$ hl.php?bereich=$1

    um über '/grundlagen' auf /hl.php?bereich=grundlagen zuzugreifen.

    Das klappt, '/grundlagen' wird in der Adresszeile allerdings automatisch zu '/grundlagen/'.

    Ein Verzeichnis grundlagen/ existiert auch physisch auf dem Server? Dann bist du auf einen (bereits bekannten) Bug gestoßen. Nach dem fixup-hook von mod_rewrite und dem internal redirect processing, läuft der fixup-hook von mod_dir des ursprünglichen Requests. Er läuft folglich noch mit einem eigentlich nicjht mehr korrekten r->uri-Wert, was nunmehr zu dem unterwünschten Redirect durch mod_dir führt.

    Du musst dir das (vereinfacht) so vorstellen:

    mod_rewrite fixup orig. request
      internal redirect
         mod_rewrite fixup internal redirect
         mod_dir fixup internal redirect
      ende internal redirect
    mod_dir fixup  orig. request <-- hier entsteht das Problem
    content handler

    Also nachdem das Processing des internal redirects abgeschlossen ist, greift erst der fixup-hook des urspr. requests von mod_dir. Das führt zu dem o.a. Fehlverhalten. Normalerweise müssten nach dem Einleiten des internal redirects durch mod_rewrite alle weiteren fixup-hooks des urpsr. requests gecanceled werden.