Caractéristiques cachées de mod rewrite

il semble y avoir un nombre décent de mod_rewrite fils flottant autour dernièrement avec un peu de confusion sur la façon dont certains aspects de la TI fonctionne. En conséquence, j'ai compilé quelques notes sur la fonctionnalité commune, et peut-être quelques nuances ennuyeuses.

quelles autres caractéristiques / problèmes courants avez-vous rencontrés en utilisant mod_rewrite ?

118
demandé sur Owen 2008-11-13 04:15:19

8 réponses

Où placer les règles de mod_rewrite

mod_rewrite les règles peuvent être placées dans le fichier httpd.conf ou dans le fichier .htaccess . si vous avez accès à httpd.conf , placer des règles ici offrira un avantage de performance (comme les règles sont traitées une fois, par opposition à chaque fois que le fichier .htaccess est appelé).

"1519420920 Exploitation" mod_rewrite "demandes de 1519430920" La journalisation

peut être activée à l'intérieur de la httpd.conf fichier (y compris les <Virtual Host> ):

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

cas d'usage courant

  1. Pour canaliser toutes les demandes à un seul point:

    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= 
    

    depuis Apache 2.2.16 vous pouvez également utiliser FallbackResource .

  2. Manipulation 301/302 redirections:

    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] 
    

    Note : les redirections externes sont implicitement 302 redirections:

    # 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. Forcer SSL

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

    • [R] ou [redirect] - forcer une redirection (par défaut à un 302 redirection temporaire)
    • [R=301] ou [redirect=301] - forcer une redirection permanente 301
    • [L] ou [last] - arrêter le processus de réécriture (voir la note ci-dessous dans les pièges courants)
    • [NC] ou [nocase] - préciser que l'appariement doit être insensible à la casse



    Utiliser la forme longue des drapeaux est souvent plus lisible et aidera les autres qui viennent lire votre code plus tard.

    Vous pouvez séparer plusieurs drapeaux avec une virgule:

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

pièges communs

  1. Mélange "1519270920 style" redirections mod_rewrite

    # Bad
    Redirect 302 /somepage.html http://example.com/otherpage.html
    RewriteEngine on
    RewriteRule ^(.*)$ index.php?query=
    
    # 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=                 
    

    Note : vous pouvez mélanger mod_alias avec mod_rewrite , mais cela implique plus de travail que la simple manipulation des redirections de base comme ci-dessus.

  2. le contexte affecte la syntaxe

    dans les fichiers .htaccess , une barre oblique principale est non utilisé dans la directive RewriteRule:

    # given: GET /directory/file.html
    
    # .htaccess
    # result: /newdirectory/file.html
    RewriteRule ^directory(.*)$ /newdirectory
    
    # .htaccess
    # result: no match!
    RewriteRule ^/directory(.*)$ /newdirectory
    
    # httpd.conf
    # result: /newdirectory/file.html
    RewriteRule ^/directory(.*)$ /newdirectory
    
    # Putting a "?" after the slash will allow it to work in both contexts:
    RewriteRule ^/?directory(.*)$ /newdirectory
    
  3. [L] n'est pas la dernière! (parfois)

    le drapeau [L] arrête le traitement de toute nouvelle réécriture des règles pour ce passage à travers l'ensemble de règles . Cependant, si L'URL a été modifiée dans ce pass et que vous êtes dans le contexte .htaccess ou dans la section <Directory> , alors votre requête modifiée sera transmise par le biais de l'analyse D'URL. le moteur de nouveau. Et au prochain passage, il pourrait correspondre à une règle différente cette fois. Si vous ne comprenez pas cela, il semble souvent que votre drapeau [L] n'a aucun effet.

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

    notre journal de réécriture montre que les règles sont exécutées deux fois et L'URL est mise à jour deux fois:

    rewrite 'dirA' -> '/dirB'
    internal redirect with /dirB [INTERNAL REDIRECT]
    rewrite 'dirB' -> '/dirC'
    

    la meilleure façon de contourner cela est d'utiliser le drapeau [END] ( voir Apache docs ) au lieu du drapeau [L] , si vous voulez vraiment arrêter tout traitement ultérieur des règles (et des passes suivantes). Cependant, le drapeau [END] n'est disponible que pour Apache v2.3.9+ , donc si vous avez v2.2 ou plus bas, vous êtes coincé avec juste le drapeau [L] .

    pour les versions précédentes, vous devez vous appuyer sur RewriteCond pour empêcher l'appariement des règles sur les passages ultérieurs du moteur de parsing URL.

    # Only process the following RewriteRule if on the first pass
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ...
    

    Ou vous devez vous assurer que votre Les règles RewriteRule sont dans un contexte (c'est-à-dire httpd.conf ) qui ne provoquera pas une nouvelle interprétation de votre requête.

202
répondu Owen 2015-12-10 03:03:48

si vous avez besoin de "bloquer" les redirections / réécritures internes de se produire dans le .htaccess, regardez le

RewriteCond %{ENV:REDIRECT_STATUS} ^$

condition, comme discuté ici .

21
répondu mromaine 2010-09-02 16:04:34

L'accord avec la directive RewriteBase:

vous avez presque toujours besoin de mettre RewriteBase. Si vous ne le faites pas, apache devine que votre base est le chemin physique du disque vers votre répertoire. Alors commence par ceci:

RewriteBase /
18
répondu Sean McMillan 2009-08-27 03:07:26

Autres Pièges:

1 - parfois c'est une bonne idée de désactiver MultiViews

Options -MultiViews

Je ne suis pas bien en vers sur toutes les fonctionnalités de MultiViews, mais je sais qu'il gâche mes règles mod_rewrite quand il est actif, parce que l'une de ses propriétés est d'essayer et de "deviner" une extension à un fichier qu'il pense que je cherche.

Je t'expliquerai: Supposons que vous ayez 2 fichiers php dans votre répertoire web, file1.php et fichier2.php et vous ajoutez ces conditions et règles à votre .htaccess:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ file1.php/ 

vous supposez que toutes les urls qui ne correspondent pas à un fichier ou à un répertoire seront saisies par file1.php. Surprise! Cette règle n'est pas respectée pour l'url http://myhost/file2/somepath . Au lieu de cela, vous êtes pris dans file2.php.

ce qui se passe, C'est que MultiViews a automatiquement deviné que l'url que vous vouliez était http://myhost/file2.php / somepath et vous y a emmené avec plaisir.

Maintenant, vous n'avez aucune idée de ce qui vient de se passer et vous êtes à ce point en questionnant tout ce que vous pensiez savoir sur mod_rewrite. Vous commencez alors à jouer avec des règles pour essayer de donner un sens à la logique derrière cette nouvelle situation, mais plus vous testez le moins de sens il fait.

Ok, en bref si vous voulez que mod_rewrite fonctionne d'une manière qui s'approche de la logique, désactiver MultiViews est un pas dans la bonne direction.

2-Activer FollowSymlinks

Options +FollowSymLinks 

celui-là, Je ne connais pas vraiment les détails de, mais je l'ai vu mentionné plusieurs fois, alors faites-le.

13
répondu Michael Ekoka 2009-08-19 10:08:10

L'équation peut être faite avec l'exemple suivant:

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 ->  is a reference to (.*)
# <> is used as an string separator/indicator, can be replaced by any other character
RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=.*$ [NC]
RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]

Équilibrage De La Charge Dynamique:

si vous utilisez mod_proxy pour équilibrer votre système, il est possible d'ajouter une plage dynamique de worker server.

RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/ [P,L]
5
répondu DrDol 2010-01-19 21:42:26

une meilleure compréhension du drapeau [L] est de mise. Le drapeau [L] est enfin, il vous suffit de comprendre ce qui va faire que votre requête sera à nouveau acheminée via le moteur de parsing URL. De la docs ( http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l ) (souligné par moi):

le drapeau [L] empêche mod_rewrite de traiter le jeu de règles. Dans la plupart des contextes, cela signifie que si la règle les matchs, pas d'autres règles seront traitées. Cela correspond à la dernière commande Perl, ou la commande break en C. Utilisez ce drapeau pour indiquer que le courant la règle devrait être appliquée immédiatement sans envisager d'autres règles.

si vous utilisez RewriteRule dans l'un ou l'autre .htaccess ou dans <Directory> sections , il est important d'avoir une certaine compréhension de comment les règles sont traitées. La simplification de la de cela est que, une fois les règles ont été traitées, la demande réécrite est rendue à le moteur D'analyse D'URL pour faire ce qu'il peut en faire. Il est possible que comme la demande réécrite est traitée, le .fichier htaccess ou <Directory> section peut être rencontré à nouveau, et ainsi le jeu de règles peut être exécuté nouveau depuis le début. Le plus souvent, cela se produira si l'un des règles provoque une redirection interne ou externe - origine du processus de demande de recommencer.

de sorte que le drapeau [L] ne cesse le traitement de toute autre règle de réécriture pour qui passe à travers l'ensemble de règles. Cependant, si votre règle marquée avec [L] a modifié la requête, et que vous êtes dans le .htaccess context ou la section <Directory> , alors votre requête modifiée sera transmise par le biais de L'analyse D'URL le moteur de nouveau. Et au prochain passage, il pourrait correspondre à une règle différente cette fois. Si vous ne comprenez pas ce qui s'est passé, il semble que votre première règle de réécriture avec le drapeau [L] n'a eu aucun effet.

la meilleure façon d'éviter cela est d'utiliser le drapeau [END] ( http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end ) au lieu du drapeau [L], si vous voulez vraiment arrêter tout traitement ultérieur des règles (et la réparation ultérieure). Cependant, le drapeau [END] est disponible uniquement pour Apache v2.3.9+, donc si vous avez v2.2 ou plus bas, vous êtes coincé avec juste le drapeau [L]. Dans ce cas, vous devez utiliser les instructions RewriteCond pour empêcher l'appariement des règles sur les passes ultérieures du moteur D'analyse D'URL. Ou vous devez vous assurer que vos RewriteRule sont dans un contexte (i.e. httpd.conf) qui n'entraînera pas une nouvelle interprétation de votre demande.

4
répondu JaredC 2015-10-04 22:20:49

un autre grand trait est rewrite-map-expansions. Ils sont particulièrement utiles si vous avez un nombre important d'hôtes / réécritures à gérer:

ils sont comme une valeur clé-remplacement:

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

alors vous pouvez utiliser un mapping dans vos règles comme:

RewriteRule ^/ex/(.*) ${examplemap:}

pour plus d'informations sur ce sujet, cliquez ici:

http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc

3
répondu B.E. 2009-08-19 10:18:10

mod_rewrite peut modifier des aspects du traitement des requêtes sans modifier L'URL, par exemple définir des variables d'environnement, définir des cookies, etc. C'est incroyablement utile.

Conditionnellement définir une variable d'environnement:

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

retourner une réponse de 503: Le drapeau RewriteRule 's [R] peut prendre une valeur non-3xx et retourner une réponse non-redirigeante, p.ex. pour les temps d'arrêt/maintenance gérés:

RewriteRule .* - [R=503,L]

sera retourner une réponse 503 (pas une redirect en soi).

aussi, mod_rewrite peut agir comme une interface super-powered vers mod_proxy, donc vous pouvez le faire au lieu d'écrire ProxyPass directives:

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

avis: Utiliser RewriteRule s et RewriteCond s pour acheminer des requêtes à différentes applications ou équilibres de charge basés sur pratiquement n'importe quel aspect concevable de la requête est tout simplement immensément puissant. Contrôle des demandes sur leur chemin vers le backend, et la possibilité de modifier les réponses en sortant, fait de mod_rewrite l'endroit idéal pour centraliser toute la configuration liée au routage.

prenez le temps de l'apprendre, ça en vaut la peine! :)

2
répondu cweekly 2015-12-29 00:16:48