Fitur tersembunyi mod_rewrite

Nov 12 2008

Tampaknya ada sejumlah mod_rewriteuntaian yang layak beredar akhir-akhir ini dengan sedikit kebingungan tentang bagaimana aspek-aspek tertentu bekerja. Akibatnya saya telah mengumpulkan beberapa catatan tentang fungsionalitas umum, dan mungkin beberapa nuansa yang mengganggu.

Apa fitur / masalah umum lain yang pernah Anda temui mod_rewrite?

Jawaban

203 Owen Nov 13 2008 at 01:15

Di mana menempatkan aturan mod_rewrite

mod_rewriteaturan dapat ditempatkan di dalam httpd.conffile, atau di dalam .htaccessfile. jika Anda memiliki akses ke httpd.conf, menempatkan aturan di sini akan menawarkan keuntungan kinerja (karena aturan diproses sekali, berbeda dengan setiap kali .htaccessfile dipanggil).

Mencatat permintaan mod_rewrite

Logging dapat diaktifkan dari dalam httpd.conffile (termasuk <Virtual Host>):

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

Kasus penggunaan umum

  1. Untuk menyalurkan semua permintaan ke satu titik:

    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 
    

    Sejak Apache 2.2.16 Anda juga dapat menggunakan FallbackResource.

  2. Menangani pengalihan 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] 
    

    Catatan : pengalihan eksternal secara implisit 302 pengalihan:

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

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

    • [R]atau [redirect]- paksa pengalihan (default ke pengalihan sementara 302)
    • [R=301]atau [redirect=301]- memaksa pengalihan permanen 301
    • [L]atau [last]- hentikan proses penulisan ulang (lihat catatan di bawah ini untuk kesalahan umum)
    • [NC]atau [nocase]- tentukan bahwa pencocokan harus peka huruf besar / kecil


    Menggunakan tanda berbentuk panjang seringkali lebih mudah dibaca dan akan membantu orang lain yang datang untuk membaca kode Anda nanti.

    Anda dapat memisahkan beberapa bendera dengan koma:

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

Jebakan umum

  1. mod_aliasPengalihan gaya pencampuran denganmod_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                 
    

    Catatan : Anda dapat mencampur mod_aliasdengan mod_rewrite, tetapi melibatkan lebih banyak pekerjaan dari sekedar penanganan pengalihan dasar seperti di atas.

  2. Konteks memengaruhi sintaks

    Di dalam .htaccessfile, garis miring di depan tidak digunakan dalam pola 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
    
  3. [L] bukan yang terakhir! (terkadang)

    The [L]bendera berhenti memproses aturan menulis ulang lebih lanjut untuk itu melewati peraturan yang ditetapkan . Namun, jika URL telah diubah di bagian itu dan Anda berada dalam .htaccesskonteks atau <Directory>bagian, maka permintaan Anda yang telah diubah akan diteruskan kembali melalui mesin pengurai URL lagi. Dan pada umpan berikutnya, kali ini mungkin cocok dengan aturan yang berbeda. Jika Anda tidak memahami hal ini, seringkali [L]benderanya tampak tidak berpengaruh.

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

    Log penulisan ulang kami menunjukkan bahwa aturan dijalankan dua kali dan URL diperbarui dua kali:

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

    Cara terbaik untuk menyiasatinya adalah dengan menggunakan [END]flag ( lihat dokumen Apache ) sebagai ganti [L]flag, jika Anda benar-benar ingin menghentikan semua pemrosesan aturan lebih lanjut (dan penerusan berikutnya). Akan tetapi, [END]flag tersebut hanya tersedia untuk Apache v2.3.9 + , jadi jika Anda memiliki v2.2 atau lebih rendah, Anda tidak dapat lagi menggunakan [L]flag tersebut.

    Untuk versi sebelumnya, Anda harus mengandalkan RewriteCondpernyataan untuk mencegah pencocokan aturan pada langkah berikutnya dari mesin parsing URL.

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

    Atau Anda harus memastikan bahwa RewriteRule Anda berada dalam konteks (yaitu httpd.conf) yang tidak akan menyebabkan permintaan Anda diurai ulang.

22 mromaine Apr 22 2010 at 06:05

jika Anda perlu 'memblokir' pengalihan / penulisan ulang internal agar tidak terjadi di .htaccess, lihat

RewriteCond %{ENV:REDIRECT_STATUS} ^$

kondisi, seperti yang dibahas di sini .

18 SeanMcMillan Aug 27 2009 at 03:07

Kesepakatan dengan RewriteBase:

Anda hampir selalu perlu menyetel RewriteBase. Jika tidak, apache menebak bahwa basis Anda adalah jalur disk fisik ke direktori Anda. Jadi mulailah dengan ini:

RewriteBase /
13 MichaelEkoka Aug 19 2009 at 10:08

Jebakan Lainnya:

1- Terkadang ide yang bagus untuk menonaktifkan MultiView

Options -MultiViews

Saya kurang paham tentang semua kemampuan MultiView, tetapi saya tahu bahwa ini mengacaukan aturan mod_rewrite saya saat aktif, karena salah satu propertinya adalah mencoba dan 'menebak' ekstensi ke file yang menurutnya sedang saya cari .

Saya akan menjelaskan: Misalkan Anda memiliki 2 file php di dir web Anda, file1.php dan file2.php dan Anda menambahkan ketentuan dan aturan ini ke .htaccess Anda:

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

Anda berasumsi bahwa semua url yang tidak cocok dengan file atau direktori akan diambil oleh file1.php. Mengherankan! Aturan ini tidak diterapkan untuk urlhttp://myhost/file2/somepath. Sebaliknya Anda dibawa ke dalam file2.php.

Apa yang terjadi adalah MultiView secara otomatis menebak bahwa url yang sebenarnya Anda inginkan adalah http://myhost/file2.php/somepath dan dengan senang hati membawamu ke sana.

Sekarang, Anda tidak tahu apa yang baru saja terjadi dan Anda pada saat itu mempertanyakan semua yang Anda pikir Anda ketahui tentang mod_rewrite. Anda kemudian mulai bermain-main dengan aturan untuk mencoba memahami logika di balik situasi baru ini, tetapi semakin Anda menguji semakin tidak masuk akal.

Ok, Singkatnya jika Anda ingin mod_rewrite bekerja dengan cara yang mendekati logika, mematikan MultiView adalah langkah yang tepat.

2- Aktifkan FollowSymlinks

Options +FollowSymLinks 

Yang itu, saya tidak begitu tahu detailnya, tapi saya sudah sering melihatnya disebutkan, jadi lakukan saja.

5 DrDol Jan 19 2010 at 21:42

Persamaan dapat dilakukan dengan contoh berikut:

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]

Penyeimbangan Beban Dinamis:

Jika Anda menggunakan mod_proxy untuk menyeimbangkan sistem Anda, dimungkinkan untuk menambahkan rentang dinamis dari server pekerja.

RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
4 JaredC Nov 14 2014 at 12:25

Pemahaman yang lebih baik tentang bendera [L] sudah beres. Bendera [L] adalah yang terakhir, Anda hanya perlu memahami apa yang akan menyebabkan permintaan Anda dirutekan lagi melalui mesin pengurai URL. Dari dokumen (http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l) (penekanan saya):

Bendera [L] menyebabkan mod_rewrite berhenti memproses set aturan. Dalam kebanyakan konteks, ini berarti bahwa jika aturan cocok, tidak ada aturan lebih lanjut yang akan diproses. Ini sesuai dengan perintah terakhir di Perl, atau perintah break di C. Gunakan tanda ini untuk menunjukkan bahwa aturan saat ini harus diterapkan segera tanpa mempertimbangkan aturan lebih lanjut.

Jika Anda menggunakan RewriteRule di file .htaccess atau di <Directory>bagian , penting untuk memiliki pemahaman tentang bagaimana aturan diproses. Bentuk yang disederhanakan adalah bahwa setelah aturan diproses, permintaan yang ditulis ulang akan dikembalikan ke mesin parsing URL untuk melakukan apa yang mungkin dilakukan dengannya. Ada kemungkinan bahwa saat permintaan penulisan ulang ditangani, file atau<Directory>bagian.htaccessdapat ditemukan lagi, dan dengan demikian kumpulan aturan dapat dijalankan lagi dari awal. Biasanya hal ini akan terjadi jika salah satu aturan menyebabkan pengalihan - baik internal maupun eksternal - yang menyebabkan proses permintaan dimulai kembali.

Jadi [L] Bendera tidak berhenti memproses aturan menulis ulang lebih lanjut untuk yang lulus melalui set aturan. Namun, jika aturan Anda yang ditandai dengan [L] mengubah permintaan tersebut, dan Anda berada dalam konteks .htaccess atau <Directory>bagian tersebut, maka permintaan yang telah diubah tersebut akan diteruskan kembali melalui mesin pengurai URL lagi. Dan pada umpan berikutnya, kali ini mungkin cocok dengan aturan yang berbeda. Jika Anda tidak memahami apa yang terjadi, sepertinya aturan penulisan ulang pertama Anda dengan bendera [L] tidak berpengaruh.

Cara terbaik untuk menyiasatinya adalah dengan menggunakan flag [END] (http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end) alih-alih flag [L], jika Anda benar-benar ingin menghentikan semua pemrosesan aturan lebih lanjut (dan pengulangan berikutnya). Akan tetapi, flag [END] hanya tersedia untuk Apache v2.3.9 +, jadi jika Anda memiliki v2.2 atau yang lebih rendah, Anda terjebak hanya dengan flag [L]. Dalam kasus ini, Anda harus mengandalkan pernyataan RewriteCond untuk mencegah pencocokan aturan pada proses berikutnya dari mesin parsing URL. Atau Anda harus memastikan bahwa RewriteRule Anda berada dalam konteks (mis. Httpd.conf) yang tidak akan menyebabkan permintaan Anda diurai ulang.

3 B.E. Aug 19 2009 at 10:18

Fitur hebat lainnya adalah rewrite-map-expansions. Mereka sangat berguna jika Anda memiliki banyak host / penulisan ulang untuk ditangani:

Mereka seperti pengganti nilai kunci:

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

Kemudian Anda dapat menggunakan pemetaan dalam aturan Anda seperti:

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

Informasi lebih lanjut tentang topik ini dapat ditemukan di sini:

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

2 cweekly Feb 12 2014 at 16:22

mod_rewrite dapat mengubah aspek penanganan permintaan tanpa mengubah URL, misalnya mengatur variabel lingkungan, mengatur cookie, dll. Ini sangat berguna.

Tetapkan variabel lingkungan secara bersyarat:

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

Kembali respon 503: RewriteRule's [R]bendera dapat mengambil nilai non-3xx dan kembali respon non-mengarahkan, misalnya untuk dikelola downtime / pemeliharaan:

RewriteRule .* - [R=503,L]

akan mengembalikan respons 503 (bukan pengalihan per se).

Selain itu, mod_rewrite dapat bertindak seperti antarmuka bertenaga super untuk mod_proxy, jadi Anda dapat melakukan ini daripada menulis ProxyPassarahan:

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

Opini: Menggunakan RewriteRules dan RewriteConds untuk merutekan permintaan ke aplikasi yang berbeda atau penyeimbang beban berdasarkan pada hampir semua aspek yang dapat dibayangkan dari permintaan itu sangat efektif. Mengontrol permintaan dalam perjalanannya ke backend, dan dapat mengubah tanggapan saat keluar, menjadikan mod_rewrite tempat yang ideal untuk memusatkan semua konfigurasi yang terkait dengan perutean.

Luangkan waktu untuk mempelajarinya, itu sangat berharga! :)