Sembra che ci sia un discreto numero di thread di mod_rewrite
che fluttuano ultimamente con un po ‘di confusione su come certi aspetti di esso funzionano. Di conseguenza ho compilato alcune note sulla funzionalità comune e forse alcune sfumature fastidiose.
Quali altre caratteristiche / problemi comuni hai incontrato usando mod_rewrite
?
mod_rewrite
regole mod_rewrite
possono essere collocate all’interno del file httpd.conf
o all’interno del file .htaccess
. se si ha accesso a httpd.conf
, l’inserimento delle regole qui offrirà un vantaggio in termini di prestazioni (poiché le regole vengono elaborate una volta, a differenza di ogni volta che viene chiamato il file .htaccess
).
La registrazione può essere abilitata dal file httpd.conf
(incluso
):
# logs can't be enabled from .htaccess # loglevel > 2 is really spammy! RewriteLog /path/to/rewrite.log RewriteLogLevel 2
Per incanalare tutte le richieste in un singolo punto:
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
Dal momento che Apache 2.2.16 è ansible utilizzare anche FallbackResource
.
Gestione dei reindirizzamenti 301/302:
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]
Nota : i reindirizzamenti esterni implicitamente sono 302 reindirizzamenti:
# 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]
Forzare SSL
RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://example.com/$1 [R,L]
Bandiere comuni:
[R]
o [redirect]
– forza un reindirizzamento (il valore predefinito è un reindirizzamento temporaneo 302) [R=301]
o [redirect=301]
– forza un 301 reindirizzamento permanente [L]
o [last]
– interrompe il processo di riscrittura (vedi la nota sotto nelle insidie più comuni) [NC]
o [nocase]
– specifica che la corrispondenza deve essere senza distinzione tra maiuscole e minuscole L’uso della lunga forma di flag è spesso più leggibile e aiuterà gli altri a leggere il tuo codice in un secondo momento.
Puoi separare più flag con una virgola:
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
Mixando mod_alias
stile mod_alias
reindirizza con 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
Nota : puoi mescolare mod_alias
con mod_rewrite
, ma richiede più lavoro rispetto alla semplice gestione dei reindirizzamenti di base come sopra.
Il contesto influisce sulla syntax
All’interno dei file .htaccess
, una barra iniziale non viene utilizzata nel modello RewriteRule:
# 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
[L] non è l’ultimo! (a volte)
Il flag [L]
interrompe l’elaborazione di ulteriori regole di riscrittura per quel passaggio attraverso il set di regole . Tuttavia, se l’URL è stato modificato in tale passaggio e ci si trova nel contesto .htaccess
o nella sezione
, la richiesta modificata verrà nuovamente passata attraverso il motore di analisi degli URL. E al prossimo passaggio, questa volta potrebbe corrispondere a una regola diversa. Se non lo capisci, spesso sembra che la tua bandiera [L]
non abbia avuto alcun effetto.
# processing does not stop here RewriteRule ^dirA$ /dirB [L] # /dirC will be the final result RewriteRule ^dirB$ /dirC
Il nostro registro di riscrittura mostra che le regole vengono eseguite due volte e l’URL viene aggiornato due volte:
rewrite 'dirA' -> '/dirB' internal redirect with /dirB [INTERNAL REDIRECT] rewrite 'dirB' -> '/dirC'
Il modo migliore per farlo è utilizzare il flag [END]
( consultare i documenti Apache ) anziché il flag [L]
, se si vuole veramente interrompere tutte le ulteriori elaborazioni delle regole (e passaggi successivi). Tuttavia, il flag [END]
è disponibile solo per Apache v2.3.9 + , quindi se hai la v2.2 o inferiore, sei bloccato solo con il flag [L]
.
Per le versioni precedenti, è necessario affidarsi alle istruzioni RewriteCond
per impedire la corrispondenza delle regole sui passaggi successivi del motore di analisi degli URL.
# Only process the following RewriteRule if on the first pass RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ...
O devi assicurarti che i tuoi RewriteRule si trovino in un contesto (es. httpd.conf
) che non farà ri-analizzare la tua richiesta.
se devi “bloccare” i reindirizzamenti / riscrittori interni dall’accaduto nel file .htaccess, dai un’occhiata a
RewriteCond %{ENV:REDIRECT_STATUS} ^$
condizione, come discusso qui .
L’accordo con RewriteBase:
È quasi sempre necessario impostare RewriteBase. Se non lo fai, apache suppone che la tua base sia il percorso fisico del disco nella tua directory. Quindi inizia con questo:
RewriteBase /
Altre insidie:
1- A volte è una buona idea disabilitare MultiView
Options -MultiViews
Non sono ben versato su tutte le funzionalità di MultiViews, ma so che danneggia le mie regole mod_rewrite quando è attivo, perché una delle sue proprietà è provare e ‘indovinare’ un’estensione di un file che pensa stia cercando .
Spiegherò: Supponi di avere 2 file php nella tua web dir, file1.php e file2.php e aggiungi queste condizioni e regola al tuo .htaccess:
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ file1.php/$1
Si presuppone che tutti gli URL che non corrispondono a un file o una directory verranno acquisiti da file1.php. Sorpresa! Questa regola non viene rispettata per l’URL http: // myhost / file2 / somepath . Invece sei preso all’interno di file2.php.
Quello che sta succedendo è che MultiViews ha immaginato automagicamente che l’url che volevi veramente fosse http: //myhost/file2.php/somepath e ti ha portato volentieri lì.
Ora, non hai idea di cosa sia appena successo e sei a quel punto mettendo in discussione tutto ciò che pensavi di sapere su mod_rewrite. Quindi inizi a giocare con le regole per cercare di dare un senso alla logica dietro questa nuova situazione, ma più stai provando, meno senso ha.
Ok, in breve, se vuoi che mod_rewrite funzioni in modo approssimativo alla logica, distriggersre MultiView è un passo nella giusta direzione.
2- abilitare FollowSymlinks
Options +FollowSymLinks
Quello, non so davvero i dettagli, ma l’ho visto menzionato molte volte, quindi fallo e basta.
L’equazione può essere fatta con il seguente esempio:
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]
Bilanciamento del carico dinamico:
Se si utilizza mod_proxy per bilanciare il sistema, è ansible aggiungere un intervallo dinamico di server di lavoro.
RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC] RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
Una migliore comprensione della [L] bandiera è in ordine. Il flag [L] è l’ ultimo, devi solo capire che cosa causerà il routing della tua richiesta attraverso il motore di analisi degli URL di nuovo. Dai documenti ( http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l ) (sottolineatura mia):
Il flag [L] fa in modo che mod_rewrite interrompa l’elaborazione del set di regole. Nella maggior parte dei contesti, ciò significa che se la regola corrisponde, non verranno elaborate ulteriori regole. Ciò corrisponde all’ultimo comando in Perl o al comando break in C. Utilizzare questo flag per indicare che la regola corrente deve essere applicata immediatamente senza considerare ulteriori regole.
Se si utilizza RewriteRule in entrambi i file .htaccess o in
, è importante avere una certa comprensione di come vengono elaborate le regole. La forma semplificata di questo è che una volta che le regole sono state elaborate, la richiesta riscritta viene restituita al motore di analisi degli URL per fare ciò che può con esso. È ansible che, man mano che la richiesta riscritta viene gestita, il file .htaccess o la sezione
possano essere incontrati di nuovo, e quindi il set di regole può essere eseguito di nuovo dall’inizio. Più comunemente ciò avverrà se una delle regole provoca un reindirizzamento, interno o esterno, che fa ricominciare il processo di richiesta.
Quindi il flag [L] smette di elaborare ulteriori regole di riscrittura per quel passaggio attraverso il set di regole. Tuttavia, se la tua regola contrassegnata con [L] ha modificato la richiesta e ti trovi nel contesto .htaccess o nella sezione
, la richiesta modificata verrà nuovamente passata attraverso il motore di analisi degli URL. E al prossimo passaggio, questa volta potrebbe corrispondere a una regola diversa. Se non capisci cosa è successo, sembra che la tua prima regola di riscrittura con il flag [L] non abbia avuto alcun effetto.
Il modo migliore per farlo è utilizzare il flag [END] ( http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end ) anziché il flag [L], se davvero vuoi fermarti tutti gli ulteriori trattamenti delle regole (e successivi riorganizzazioni). Tuttavia, il flag [END] è disponibile solo per Apache v2.3.9 +, quindi se hai la v2.2 o inferiore, sei bloccato solo con il flag [L]. In questo caso, è necessario affidarsi alle istruzioni RewriteCond per impedire la corrispondenza delle regole sui passaggi successivi del motore di analisi degli URL. O devi assicurarti che i tuoi RewriteRule si trovino in un contesto (es. Httpd.conf) che non farà ri-analizzare la tua richiesta.
Un’altra grande caratteristica sono le espansioni della mappa della riscrittura. Sono particolarmente utili se hai una quantità enorme di host / riscritture da gestire:
Sono come una sostituzione di valore chiave:
RewriteMap examplemap txt:/path/to/file/map.txt
Quindi puoi utilizzare una mapping delle tue regole come:
RewriteRule ^/ex/(.*) ${examplemap:$1}
Maggiori informazioni su questo argomento possono essere trovate qui:
http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc
mod_rewrite può modificare aspetti della gestione delle richieste senza alterare l’URL, ad esempio impostare variabili d’ambiente, impostare cookie, ecc. Ciò è incredibilmente utile.
Imposta condizionatamente una variabile di ambiente:
RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC] RewriteRule .* - [E=MY_ENV_VAR:%b]
Restituisce una risposta 503: il flag [R]
RewriteRule
può assumere un valore non-3xx e restituire una risposta non di reindirizzamento, ad esempio per downtime / manutenzione gestiti:
RewriteRule .* - [R=503,L]
restituirà una risposta 503 (non un reindirizzamento di per sé).
Inoltre, mod_rewrite può agire come un’interfaccia potenziata a mod_proxy, quindi puoi farlo invece di scrivere le direttive ProxyPass
:
RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
Opinione: l’utilizzo di RewriteRule
s e RewriteCond
per indirizzare le richieste a diverse applicazioni o load balancer in base a qualsiasi aspetto concepibile della richiesta è immensamente potente. Controllando le richieste mentre si dirigono verso il back-end, e potendo modificare le risposte al loro ritorno, rende mod_rewrite il posto ideale per centralizzare tutte le configurazioni relative al routing.
Prenditi il tempo per impararlo, ne vale la pena! 🙂