terminal42 / contao-url-rewrite

Provides a back end module in Contao that allows you to specify url rewrites that are added to the Symfony Route collection
MIT License
15 stars 4 forks source link

Probleme mit "/alias" zu "/alias/" #34

Closed grummbeer closed 1 year ago

grummbeer commented 2 years ago

Hi Leute,

folgender Fall: Das Suffix wurde von .html nach / umgestellt. Dafür habe ich eine Regel angelegt.

# app/config/parameters.yaml
contao:
    url_suffix: "/"
Pfad: 
     /{path}{suffix}
Extra:
   - path: .*
   - suffix: \.html$
Antwort-URL:
    /{path}/

Das hat soweit funktioniert. Wenn es besser geht, bin ich offen für Vorschläge :-)

Nun gibt es aber Seiten, deren Alias ohne .html in z.B. Printmedien verwendet wurde.

Beispiel:

Pfad: 
     /datenschutz
Antwort-URL:
    /{{link_url::123}}

Das hat zuverlässig dafür gesorgt (Danke!), dass der URL /datenschutz zu /datenschutz.html umgelenkt wurde.

Erwartet hatte ich jetzt, dass diese Regel auch mit dem / als suffix einfach weiterhin funktioniert. Tut sie aber nicht, nun produziert die Regel eine Schleife: ERR_TOO_MANY_REDIRECTS.

Beide URLs werden getroffen. Das Einschränken des URL scheint auch nicht zu funktionieren.

Pfad: 
     /{path}
Extra:
   - path: datenschutz$
Antwort-URL:
    /{{link_url::123}}

Was mache ich falsch?

Toflar commented 1 year ago

Das hier ist der Bugtracker. Für Support: https://contao.org/de/support.html

grummbeer commented 1 year ago

Der Bug besteht darin, dass man keine Umleitung anlegen kann, wenn der Suffix ein "/" ist und der redirectPath einem Alias entspricht.

suffix: /

redirectPath: /alias
responseUri: /alias/

url_rewrite_1    GET      ANY      ANY    /alias                         
tl_page.2        ANY      http     ANY    /alias{!parameters}/ 

Dies führt zu einer Umleitungsschleife.

Wenn diese ein gewolltes Verhalten ist, vervollständige ich gerne die entsprechende Stelle in den Docs oder hier in der README.

Kein Suffix oder Suffix / kollidiert irgendwie mit dem RedirectUrlMatcher RedirectableUrlMatcher?

aschempp commented 1 year ago

soweit mir bekannt ist, schreibt Contao (bzw. Symfony) eine URL ohne Slash automatisch auf mit Slash um, wenn dieser konfiguriert ist. Hast du es mal ohne URL-Rewrite versucht?

grummbeer commented 1 year ago

Ja und ja, das Verhalten ist wie hier Dokumentiert: https://symfony.com/doc/5.4/routing.html#redirecting-urls-with-trailing-slashes. Aktuell kann ich aber nur den Weg /alias/ > /alias und nicht vice versa beobachten.

contao 4.13.15, frisch aufgesetzt.

Fall 1. Suffix '' (Ohne Suffix)

suffix: ''

  url_rewrite_qr_code                    GET      ANY      ANY    /url_rewrite_qr_code/{url}     
  tl_page.1.root                         ANY      http     ANY    /                              
  tl_page.2                              ANY      http     ANY    /alias{!parameters}            
  tl_page.1                              ANY      http     ANY    /index{!parameters}    

Resultat:

GET /alias > 200
GET /alias/ > 301 > /alias > 200

Fall 2. Suffix '/'

suffix: /

  url_rewrite_qr_code                    GET      ANY      ANY    /url_rewrite_qr_code/{url}     
  tl_page.1.root                         ANY      http     ANY    /                              
  tl_page.2                              ANY      http     ANY    /alias{!parameters}/           
  tl_page.1                              ANY      http     ANY    /index{!parameters}/  

Resultat:

GET /alias/ > 200
GET /alias > 404

Die Fälle unterscheidet sich im Verhalten. Es fühlt sich nicht konsistent an, wenn der slash automatisch entfernt wird (Fall 1), aber im umgekehrten Falle (Fall 2) nicht angehängt wird. Also /alias/ wird zu /alias, aber /alias/ wird nicht zu /alias.

Es ist nicht das was man erwartet. Der Suffix sollte beliebig sein, ohne automatische Manipulation.

Wenn ich, wie hier https://github.com/symfony/symfony/pull/33362#issuecomment-526251779 angemerkt, im Contao\UrlMatcher (https://github.com/contao/contao/blob/4.13/core-bundle/src/Routing/Matcher/UrlMatcher.php#L23) statt den RedirectableUrlMacher den Symfony eigenen UrlMatcher erweitere, ist das Verhalten eher wie erwartet.

use Symfony\Component\Routing\Matcher\UrlMatcher AS SymfonyUrlMatcher;
class UrlMatcher extends SymfonyUrlMatcher implements FinalMatcherInterface

Resultat:

GET /alias > 200
GET /alias/ > 404 (statt > 301 > /alias > 200)

Möglicherweise wäre es überlegenswert auf den RedirectableUrlMacher zu verzichten, einfach damit das Verhalten so ist wie man es erwartet. Möchte man willentlich den slash (irgendwas sonst) entfernen oder anhängen bzw. umleiten, sollten man das url-rewrite bundle benutzen :-)

OK, das betrifft Symfony/Contao, und jetzt wieder zum Problem.

contao-url-rewrite

suffix: /

  url_rewrite_qr_code                    GET      ANY      ANY    /url_rewrite_qr_code/{url}     
  tl_page.1.root                         ANY      http     ANY    /                              
  tl_page.2                              ANY      http     ANY    /alias{!parameters}/           
  tl_page.1                              ANY      http     ANY    /index{!parameters}/  

Resultat:

GET /alias/ > 200
GET /alias > 404

Jetzt lege ich über das Backend eine Regel an, um /alias zu /alias/ umzuleiten, da dies - wie erwartet - nicht automatisch geschieht.

redirectPath: /alias
responseUri: {{link_url::2}} > "/alias/"

  url_rewrite_qr_code                    GET      ANY      ANY    /url_rewrite_qr_code/{url}     
  url_rewrite_0                          GET      ANY      ANY    /alias                         
  tl_page.1.root                         ANY      http     ANY    /                              
  tl_page.2                              ANY      http     ANY    /alias{!parameters}/           
  tl_page.1                              ANY      http     ANY    /index{!parameters}/   

Resultat:

GET /alias > 301 > /alias/
GET /alias/ > 301 > /alias
GET /alias > 301 > /alias/
…

Umleitungsschleife ERR_TOO_MANY_REDIRECTS

Gelöst habe ich das bisher über die .htaccess RewriteRule ^alias$ /alias/ [L,R=301], was auch gleichzeitig belegt, dass dieses Verhalten irgendwo in der Interna begründet sein muss. Ich hoffe die Ausführlichkeit hat dazu beigetragen den Sachverhalt so klar wie möglich zu machen.

grummbeer commented 1 year ago

Hab’s in einer frischen 5.4er Installation ausprobiert.

app_slashless:
  path: /slashless
  controller: App\Controller\SlashController::slashless
app_slash:
  path: /slash/
  controller: App\Controller\SlashController::slash

Ich kann bestätigen, dass beide Routen genau wie hier¹ beschrieben funktionieren und jeweils einen Redirect auslösen.

/slashless/ > 301 > /slashless
/slash > 301 > /slash/

Contao verhält sich so nicht. Soll ich da ein Ticket im Contao repo aufmachen?

¹ https://symfony.com/doc/5.4/routing.html#redirecting-urls-with-trailing-slashes

aschempp commented 1 year ago

was ist genau das Problem und was möchtest du erreichen? Symfony leitet ohne Slash auf mit Slash um, aber nicht umgekehrt. Contao auch. Das ist Absicht. Alles andere kannst du doch selber weiterleiten?

grummbeer commented 1 year ago

Danke für Deine Geduld.

was möchtest du erreichen?

  1. Der Suffix soll "/" sein, bzw. wurde so eingestellt.
  2. Der URL /datenschutz soll auf den URL /datenschutz/ weiterleiten.

was ist genau das Problem?

  1. Der URL /datenschutz mündet in einer 404 NOT FOUND Antwort.
  2. Der Versuch über die "URL Umschreibregeln" eine Regel anzulegen (/datenschutz > /datenschutz/, mündet in einer Umleitungsschleife.

Symfony leitet ohne Slash auf mit Slash um, aber nicht umgekehrt. Contao auch. Das ist Absicht.

Das ist mein Anwendungsfall. Es wird aber nicht auf "mit Slash" umgeleitet. Ich beoachte den umgekehrten Fall. "Mit Slash" wird auf "ohne Slash" umgeleitet, aber nicht umgekehrt.

Wenn das Absicht ist, wie muss dann die Umschreibregel lauten, damit ich von "ohne Slash" auf "mit Slash" umleiten kann ohne in die Umleitungsschleife zu geraten? Ich suche das Äquivalent zur Regel RewriteRule ^datenschutz$ /datenschutz/ [L,R=301] in der .htaccess.

Danke.

https://user-images.githubusercontent.com/67791701/212912278-63eabfe3-8589-4206-9842-487120adabca.mp4

aschempp commented 1 year ago

Kannst du in der Browser-Konsole nachvollziehen welche Umleitungen zu einer Endlosschleife führen? Mit Firefox sollte das gut gehen wenn du die Netzwerk-Konsole nicht leeren lässt.

grummbeer commented 1 year ago

Es trifft alle Umleitungen, wenn requestPath gleich einem existierenden Alias ist und als urlSuffix ein / gewählt wurde.

Das Video zeigt folgendes:

  1. Einstellungen
    • urlPrefix: /
  2. Seite anlegen
    • Alias: datenschutz
  3. Test im Browser
    • /datenschutz/ > 200
    • /datenschutz > 404 (Soll aber aufrufbar sein, da der URL in Druckerzeugnissen publiziert ist.)
  4. UrlRewrite Regel anlegen
    • requestPath: /datenschutz
    • responseUri: /datenschutz/
  5. Test im Browser
    • /datenschutz > 301 > /datenschutz/ > 301 > /datenschutz … Schleife

Die (UrlRewrite-)Route matcht sich selbst?

Möglicherweise müssten die Contao-Route vor der UrlRewrite-Route matchen, die Priorisierung erfolgt aber nur innerhalb der jeweiligen "Gruppe". Also 1. Eigene Routen, 2. Routen aus UrlRewrite und dann erst 3. Routen aus Contao-Alias.

Vielleicht kannst Du es nachstellen, das zeigt wohl mehr als alles was sonst hier steht. Gerne erteile ich einen Auftag dafür.