Referensi: mod_rewrite, penulisan ulang URL, dan “tautan cantik” dijelaskan

142

"Tautan cantik" adalah topik yang sering diminta, tetapi jarang dijelaskan sepenuhnya. mod_rewrite adalah salah satu cara untuk membuat "tautan yang cantik", tetapi kompleks dan sintaksisnya sangat singkat, sulit untuk grok, dan dokumentasi mengasumsikan tingkat kemahiran HTTP tertentu. Dapatkah seseorang menjelaskan secara sederhana bagaimana "tautan cantik" bekerja dan bagaimana mod_rewrite dapat digunakan untuk membuatnya?

Nama umum lainnya, alias, istilah untuk URL bersih: URL tenang , URL yang mudah digunakan, URL SEO -friendly , slugging , dan URL MVC (mungkin salah nama)

tipuan
sumber
2
Slug atau Slugging adalah alias / istilah umum lainnya untuk url cantik.
Mike B
2
@ Mike Sort of, tetapi siput sering menjadi bagian dari URL yang cantik. Siput sangat khusus ketika, misalnya, judul artikel diubah menjadi bentuk URL-friendly yang kemudian bertindak sebagai pengidentifikasi artikel itu. Begitu reference-mod-rewrite-url-rewriting-explainedjuga siput, /questions/20563772/reference-mod-rewrite-url-rewriting-explainedadalah URL yang cantik.
deceze
2
Saya pikir tag .htaccessdan mod-rewriteharus diperbarui untuk menyertakan tautan ke pertanyaan ini, karena mencakup banyak dari apa yang ditanyakan secara teratur. Pikiran?
Mike Rockétt

Jawaban:

110

Untuk memahami apa yang mod_rewrite lakukan, pertama-tama Anda perlu memahami cara kerja server web. Server web merespons permintaan HTTP . Permintaan HTTP di tingkat paling dasar terlihat seperti ini:

GET /foo/bar.html HTTP/1.1

Ini adalah permintaan sederhana dari browser ke server web yang meminta URL /foo/bar.html darinya. Penting untuk ditekankan bahwa itu tidak meminta file , hanya meminta beberapa URL sewenang-wenang. Permintaan juga dapat terlihat seperti ini:

GET /foo/bar?baz=42 HTTP/1.1

Ini sama validnya dengan permintaan untuk URL, dan jelas tidak ada hubungannya dengan file.

Server web adalah aplikasi yang mendengarkan pada port, menerima permintaan HTTP yang masuk pada port itu dan mengembalikan respons. Server web sepenuhnya bebas untuk menanggapi permintaan apa pun yang menurutnya sesuai / dengan cara apa pun yang telah Anda konfigurasikan untuk merespons. Respons ini bukan file, ini respons HTTP yang mungkin atau mungkin tidak ada hubungannya dengan file fisik pada disk apa pun. Server web tidak harus Apache, ada banyak server web lain yang semuanya hanya program yang berjalan terus-menerus dan dilampirkan ke port yang merespons permintaan HTTP. Anda dapat menulis sendiri. Paragraf ini dimaksudkan untuk menceraikan Anda dari anggapan bahwa URL secara langsung menyamakan file, yang sangat penting untuk dipahami. :)

Konfigurasi default sebagian besar server web adalah mencari file yang cocok dengan URL pada hard disk. Jika akar dokumen server diatur ke, katakanlah, /var/wwwmungkin terlihat apakah file tersebut /var/www/foo/bar.htmlada dan sajikan jika demikian. Jika file berakhir dengan ".php" itu akan memanggil penerjemah PHP dan kemudian mengembalikan hasilnya. Semua asosiasi ini sepenuhnya dapat dikonfigurasi; file tidak harus diakhiri dengan ".php" agar server web dapat menjalankannya melalui penerjemah PHP, dan URL tidak harus mencocokkan file tertentu pada disk untuk sesuatu terjadi.

mod_rewrite adalah cara untuk menulis ulang penanganan permintaan internal. Ketika server web menerima permintaan untuk URL /foo/bar, Anda dapat menulis ulang URL itu menjadi sesuatu yang lain sebelum server web akan mencari file pada disk untuk mencocokkannya. Contoh sederhana:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

Aturan ini mengatakan kapan saja permintaan cocok dengan "/ foo / bar", tulis ulang menjadi "/ foo / baz". Permintaan kemudian akan ditangani seolah-olah /foo/baztelah diminta sebagai gantinya. Ini dapat digunakan untuk berbagai efek, misalnya:

RewriteRule (.*) $1.html

Aturan ini cocok dengan apa pun ( .*) dan menangkapnya ( (..)), lalu menulis ulang untuk menambahkan ".html". Dengan kata lain, jika /foo/barURL yang diminta, itu akan ditangani seolah-olah /foo/bar.htmltelah diminta. Lihat http://regular-expressions.info untuk informasi lebih lanjut tentang pencocokan ekspresi reguler, penangkapan, dan penggantian.

Aturan lain yang sering ditemui adalah ini:

RewriteRule (.*) index.php?url=$1

Ini, sekali lagi, cocok dengan apa pun dan menulis ulang ke file index.php dengan URL yang awalnya diminta ditambahkan dalam urlparameter kueri. Yaitu, untuk setiap dan semua permintaan yang masuk, file index.php dieksekusi dan file ini akan memiliki akses ke permintaan asli $_GET['url'], sehingga dapat melakukan apa pun yang diinginkan.

Terutama Anda memasukkan aturan penulisan ulang ini ke file konfigurasi server web Anda . Apache juga memungkinkan Anda untuk meletakkannya di file yang disebut di .htaccessdalam root dokumen Anda (yaitu di sebelah file .php Anda).

* Jika diizinkan oleh file konfigurasi Apache utama; itu opsional, tetapi sering diaktifkan.

Apa yang tidak dilakukan mod_rewrite

mod_rewrite tidak secara ajaib membuat semua URL Anda "cantik". Ini adalah kesalahpahaman umum. Jika Anda memiliki tautan ini di situs web Anda:

<a href="https://stackoverflow.com/my/ugly/link.php?is=not&amp;very=pretty">

tidak ada yang bisa dilakukan mod_rewrite untuk membuatnya cantik. Untuk menjadikan ini tautan yang cantik, Anda harus:

  1. Ubah tautan ke tautan yang cantik:

    <a href="https://stackoverflow.com/my/pretty/link">
    
  2. Gunakan mod_rewrite di server untuk menangani permintaan ke URL /my/pretty/linkmenggunakan salah satu metode yang dijelaskan di atas.

(Orang dapat menggunakan mod_substitutebersama-sama untuk mengubah halaman HTML keluar dan tautannya yang terkandung. Meskipun ini biasanya lebih banyak upaya daripada hanya memperbarui sumber daya HTML Anda.)

Ada banyak yang dapat dilakukan mod_rewrite dan aturan pencocokan yang sangat rumit yang dapat Anda buat, termasuk merantai beberapa penulisan ulang, memproksi permintaan ke layanan atau mesin yang sama sekali berbeda, mengembalikan kode status HTTP tertentu sebagai tanggapan, mengarahkan permintaan, dll. Ini sangat kuat dan dapat digunakan untuk Sangat bagus jika Anda memahami mekanisme permintaan-respons HTTP mendasar. Itu tidak secara otomatis membuat tautan Anda cantik.

Lihat dokumentasi resmi untuk semua kemungkinan bendera dan opsi.

tipuan
sumber
6
Mungkin menyebutkan arahan FallbackResource yang diperkenalkan di versi 2.2.16 sebagai cara yang disukai untuk menulis ulang ke operator.
Darsstar
78

Untuk memperluas jawaban tipuan , saya ingin memberikan beberapa contoh dan penjelasan tentang beberapa fungsi mod_rewrite lainnya.

Semua contoh di bawah ini mengasumsikan bahwa Anda sudah termasuk RewriteEngine Ondalam .htaccessfile Anda .

Tulis ulang Contoh

Mari kita ambil contoh ini:

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]

Aturan dibagi menjadi 4 bagian:

  1. RewriteRule - memulai aturan penulisan ulang
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - Ini disebut polanya, namun saya hanya akan menyebutnya sebagai sisi kiri dari aturan - apa yang ingin Anda tulis ulang dari
  3. blog/index.php?id=$1&title=$2 - Disebut substitusi, atau sisi kanan aturan penulisan ulang - apa yang ingin Anda tulis ulang
  4. [NC,L,QSA] adalah bendera untuk aturan penulisan ulang, dipisahkan oleh koma, yang akan saya jelaskan lebih lanjut nanti

Penulisan ulang di atas akan memungkinkan Anda untuk menautkan ke sesuatu seperti /blog/1/foo/dan itu benar-benar akan memuat /blog/index.php?id=1&title=foo.

Sisi kiri aturan

  • ^menunjukkan awal nama halaman - jadi itu akan menulis ulang example.com/blog/...tetapi tidakexample.com/foo/blog/...
  • Setiap set (…)tanda kurung menunjukkan ekspresi reguler yang dapat kita tangkap sebagai variabel di sisi kanan aturan. Dalam contoh ini:
    • Set kurung pertama - ([0-9]+)- cocok dengan string dengan panjang minimal 1 karakter dan hanya dengan nilai numerik (yaitu 0-9). Ini dapat dirujuk dengan $1di sisi kanan aturan
    • Set tanda kurung kedua cocok dengan string dengan panjang minimal 1 karakter, hanya berisi karakter alfanumerik (AZ, az, atau 0-9) atau -atau +(catatan +lolos dengan backslash karena tanpa melarikan diri itu akan dijalankan sebagai regex karakter pengulangan ). Ini dapat dirujuk dengan $2di sisi kanan aturan
  • ?berarti karakter sebelumnya adalah opsional, jadi dalam hal ini keduanya /blog/1/foo/dan /blog/1/fooakan menulis ulang ke tempat yang sama
  • $ menunjukkan ini adalah akhir dari string yang ingin kita cocokkan

Bendera

Ini adalah opsi yang ditambahkan dalam tanda kurung di akhir aturan penulisan ulang Anda untuk menentukan kondisi tertentu. Sekali lagi, ada banyak flag berbeda yang dapat Anda baca di dokumentasi , tetapi saya akan membaca beberapa flag yang lebih umum:

NC

Bendera tanpa huruf besar berarti aturan penulisan ulang tidak sensitif huruf besar, jadi untuk contoh aturan di atas ini berarti keduanya /blog/1/foo/dan /BLOG/1/foo/(atau variasi apa pun dari ini) akan cocok.

L

Bendera terakhir menunjukkan bahwa ini adalah aturan terakhir yang harus diproses. Ini berarti bahwa jika dan hanya jika aturan ini cocok, tidak ada aturan lebih lanjut yang akan dievaluasi dalam proses pemrosesan penulisan ulang saat ini. Jika aturan tidak cocok, semua aturan lainnya akan dicoba berurutan seperti biasa. Jika Anda tidak mengatur Lbenderanya, semua aturan berikut akan diterapkan ke URL yang ditulis ulang sesudahnya.

END

Karena Apache 2.4 Anda juga dapat menggunakan [END]flag. Aturan yang cocok dengannya akan sepenuhnya menghentikan pemrosesan alias / penulisan ulang lebih lanjut. (Bahwa [L]bendera seringkali dapat memicu putaran kedua, misalnya ketika menulis ulang masuk atau keluar dari subdirektori.)

QSA

Bendera append string string memungkinkan kita untuk mengirimkan variabel tambahan ke URL yang ditentukan yang akan ditambahkan ke parameter get asli. Sebagai contoh kita ini berarti sesuatu seperti /blog/1/foo/?comments=15akan dimuat/blog/index.php?id=1&title=foo&comments=15

R

Bendera ini bukan yang saya gunakan dalam contoh di atas, tetapi bendera yang menurut saya layak disebutkan. Ini memungkinkan Anda untuk menentukan pengalihan http, dengan opsi untuk memasukkan kode status (misalnya R=301). Sebagai contoh jika Anda ingin melakukan pengalihan 301 di / myblog / ke / blog / Anda cukup menulis aturan seperti ini:

RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]

Kondisi Penulisan Ulang

Kondisi penulisan ulang membuat penulisan ulang menjadi lebih kuat, memungkinkan Anda menentukan penulisan ulang untuk situasi yang lebih spesifik. Ada banyak kondisi yang dapat Anda baca di dokumentasi , tetapi saya akan menyentuh beberapa contoh umum dan menjelaskannya:

# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Ini adalah praktik yang sangat umum, yang akan menambah dengan domain Anda www.(jika belum ada di sana) dan menjalankan pengalihan 301. Misalnya, memuatnya http://example.com/blog/akan mengarahkan Anda kehttp://www.example.com/blog/

# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/$1 [L]

Ini sedikit kurang umum, tetapi merupakan contoh yang baik dari aturan yang tidak dijalankan jika nama file adalah direktori atau file yang ada di server.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] hanya akan menjalankan penulisan ulang untuk file dengan ekstensi file jpg, jpeg, gif atau png (case-sensitive).
  • %{REQUEST_FILENAME} !-f akan memeriksa untuk melihat apakah file ada di server saat ini, dan hanya menjalankan penulisan ulang jika tidak
  • %{REQUEST_FILENAME} !-d akan memeriksa untuk melihat apakah file ada di server saat ini, dan hanya menjalankan penulisan ulang jika tidak
  • Penulisan ulang akan mencoba memuat file yang sama di domain lain
Nick
sumber
39

Referensi

Stack Overflow memiliki banyak sumber daya hebat lainnya untuk memulai:

Dan bahkan gambaran umum regex ramah baru:

Placeholder bekas pakai

  • .*cocok dengan apa pun, bahkan string kosong. Anda tidak ingin menggunakan pola ini di mana-mana, tetapi sering kali dalam aturan fallback terakhir.
  • [^/]+lebih sering digunakan untuk segmen jalur. Ini cocok dengan apa pun kecuali garis miring.
  • \d+ hanya cocok dengan string numerik.
  • \w+cocok dengan karakter alfanumerik. Ini pada dasarnya singkatan [A-Za-z0-9_].
  • [\w\-]+untuk segmen jalur gaya "slug", menggunakan huruf, angka, tanda hubung - dan _
  • [\w\-.,]+menambahkan titik dan koma. Lebih suka \-lari kabur di […]charclass.
  • \.menunjukkan periode literal. Kalau tidak, di .luar […]adalah placeholder untuk simbol apa pun.

Masing-masing penampung ini biasanya dibungkus dengan (…)tanda kurung sebagai kelompok tangkap. Dan seluruh pola sering di ^………$spidol awal + akhir. Mengutip "pola" adalah opsional.

RewriteRules

Contoh-contoh berikut adalah PHP-centric dan sedikit lebih inkremental, lebih mudah diadaptasi untuk kasus serupa. Itu hanya ringkasan, sering menautkan ke lebih banyak variasi atau tanya jawab secara terperinci.

  • Pemetaan statis
    /contact,/about

    Memendekkan beberapa nama halaman menjadi skema file internal adalah yang paling sederhana:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • Pengidentifikasi numerik
    /object/123

    Memperkenalkan cara pintas seperti http://example.com/article/531ke skrip PHP yang ada juga mudah. Tempat penampung angka hanya dapat dipetakan kembali ke $_GETparameter:

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
     #                      └───────────────────────────┘
    
  • Penampung gaya-siput
    /article/with-some-title-slug

    Anda dapat dengan mudah memperluas aturan itu untuk memungkinkan /article/title-stringplaceholder:

     RewriteRule ^article/([\w-]+)$    article-show.php?title=$1
     #                       └────────────────────────────────┘
    

    Perhatikan bahwa skrip Anda harus dapat (atau disesuaikan) untuk memetakan judul-judul itu kembali ke id-database. RewriteRules saja tidak dapat membuat atau menebak informasi dari udara kosong.

  • Siput dengan awalan angka
    /readable/123-plus-title

    Karenanya Anda akan sering melihat /article/529-title-slugjalur campuran yang digunakan dalam praktik:

     RewriteRule ^article/(\d+)-([\w-]+)$    article.php?id=$1&title=$2
     #                      └───────────────────────────────┘
    

    Sekarang Anda bisa melewatkan melewati title=$2saja, karena skrip Anda biasanya akan bergantung pada database-id. The -title-slugtelah menjadi dekorasi URL sewenang-wenang.

  • Keseragaman dengan daftar alternatif
    /foo/… /bar/… /baz/…

    Jika Anda memiliki aturan serupa untuk beberapa jalur halaman virtual, maka Anda dapat mencocokkan dan memadatkannya dengan |daftar alternatif. Dan lagi, tetapkan kembali ke parameter GET internal:

     #                               ┌─────────────────────────┐
     RewriteRule ^(blog|post|user)/(\w+)$  disp.php?type=$1&id=$2
     #               └───────────────────────────────────┘
    

    Anda dapat membaginya menjadi individu RewriteRulejika ini menjadi terlalu kompleks.

  • Mengirim URL terkait ke berbagai backend
    /date/SWITCH/backend

    Penggunaan daftar alternatif yang lebih praktis adalah memetakan jalur permintaan ke skrip yang berbeda. Misalnya untuk memberikan URL yang seragam untuk aplikasi web yang lebih lama dan lebih baru berdasarkan tanggal:

     #                   ┌─────────────────────────────┐
     #                   │                 ┌───────────┼───────────────┐
     RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=$2
     RewriteRule ^blog/(\d+)/([\d-]+)/?$  modern/blog/index.php?start=$2
     #                          └──────────────────────────────────────┘
    

    Ini hanya memetakan ulang 2009-2011 posting ke satu skrip, dan semua tahun lainnya secara implisit ke penangan lain. Perhatikan aturan yang lebih spesifik lebih dulu . Setiap skrip mungkin menggunakan paret GET yang berbeda.

  • Pembatas lain dari sekadar /garis miring
    /user-123-name

    Anda paling sering melihat RewriteRules untuk mensimulasikan struktur direktori virtual. Tetapi Anda tidak dipaksa untuk tidak kreatif. Anda juga bisa menggunakan -tanda hubung untuk segmentasi atau struktur.

     RewriteRule ^user-(\d+)$    show.php?what=user&id=$1
     #                   └──────────────────────────────┘
     # This could use `(\w+)` alternatively for user names instead of ids.
    

    Untuk /wiki:section:Page_Nameskema yang juga umum :

     RewriteRule ^wiki:(\w+):(\w+)$  wiki.php?sect=$1&page=$2 
     #                   └─────┼────────────────────┘       │
     #                         └────────────────────────────┘
    

    Kadang-kadang itu cocok untuk bergantian antara /-delimiters dan :atau .dalam aturan yang sama bahkan. Atau minta dua RewriteRules lagi untuk memetakan varian ke skrip yang berbeda.

  • Opsional /garis miring slash
    /dir=/dir/

    Saat memilih jalur gaya direktori, Anda dapat membuatnya dapat dicapai dengan dan tanpa final /

     RewriteRule ^blog/([\w-]+)/?$  blog/show.php?id=$1
     #                         ┗┛
    

    Sekarang ini menangani keduanya http://example.com/blog/123dan /blog/123/. Dan /?$pendekatannya mudah ditambahkan ke aturan RewriteR lainnya.

  • Segmen fleksibel untuk jalur virtual
    .*/.*/.*/.*

    Sebagian besar aturan yang Anda temui akan memetakan sekumpulan /…/segmen jalur sumber daya yang dibatasi ke parameter GET individual. Beberapa skrip menangani sejumlah opsi variabel . Mesin regexp Apache tidak memungkinkan untuk memilih jumlah yang sewenang-wenang dari mereka. Tetapi Anda dapat dengan mudah mengembangkannya menjadi aturan yang memblokir diri Anda sendiri:

     Rewriterule ^(\w+)/?$                in.php?a=$1
     Rewriterule ^(\w+)/(\w+)/?$          in.php?a=$1&b=$2
     Rewriterule ^(\w+)/(\w+)/(\w+)/?$    in.php?a=$1&b=$2&c=$3
     #              └─────┴─────┴───────────────────┴────┴────┘
    

    Jika Anda memerlukan hingga lima segmen jalur, salin skema ini ke dalam lima aturan. Anda tentu saja dapat menggunakan yang lebih spesifik[^/]+ masing-masing placeholder yang . Di sini pemesanan tidak begitu penting, karena tidak ada yang tumpang tindih. Jadi memiliki jalur yang paling sering digunakan pertama kali tidak apa-apa.

    Atau Anda dapat menggunakan parameter array PHP melalui ?p[]=$1&p[]=$2&p[]=3 string kueri di sini - jika skrip Anda hanya menginginkannya pre-split. (Meskipun lebih umum menggunakan aturan catch-all, dan biarkan skrip itu sendiri memperluas segmen dari REQUEST_URI.)

    Lihat juga: Bagaimana cara mengubah segmen jalur URL saya menjadi pasangan nilai kunci string kueri?

  • Segmen opsional
    prefix/opt?/.*

    Variasi umum adalah memiliki awalan opsional di dalam aturan. Ini biasanya masuk akal jika Anda memiliki string statis atau placeholder yang lebih terbatas di sekitar:

      RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$  ?main=$1&opt=$2&suffix=$3
    

    Sekarang pola yang lebih kompleks di (?:/([^/])+)?sana hanya membungkus kelompok yang tidak menangkap (?:…) , dan menjadikannya opsional )?. Tempat penampung yang ada ([^/]+)akan menjadi pola substitusi $2, tetapi kosong jika tidak ada /…/jalan tengah .

  • Tangkap sisanya
    /prefix/123-capture/…/*/…whatever…

    Seperti yang dikatakan sebelumnya, Anda tidak sering menginginkan pola penulisan ulang yang terlalu umum. Namun masuk akal untuk menggabungkan perbandingan statis dan spesifik dengan .*kadang - kadang.

     RewriteRule ^(specific)/prefix/(\d+)(/.*)?$  speci.php?id=$2&otherparams=$2
    

    Ini memilih semua /…/…/…segmen jalur tambahan. Yang kemudian tentu saja memerlukan skrip penanganan untuk membaginya, dan variabl-ify diekstraksi parameter itu sendiri (yang adalah apa yang dilakukan kerangka kerja "MVC" ).

  • Membuntuti file "ekstensi"
    /old/path.HTML

    URL tidak benar-benar memiliki ekstensi file. Itulah keseluruhan referensi ini (= URL adalah pelacak virtual, tidak harus berupa gambar sistem file langsung). Namun jika Anda memiliki pemetaan file 1: 1 sebelumnya, Anda dapat membuat aturan yang lebih sederhana:

     RewriteRule  ^styles/([\w\.\-]+)\.css$  sass-cache.php?old_fn_base=$1
     RewriteRule  ^images/([\w\.\-]+)\.gif$  png-converter.php?load_from=$2
    

    Kegunaan umum lainnya adalah memetakan kembali .htmljalur yang usang ke .phppenangan yang lebih baru , atau hanya dengan alias nama direktori hanya untuk file individu (aktual / nyata).

  • Ping-Pong (pengalihan dan penulisan ulang serempak)
    /ugly.html← →/pretty

    Jadi pada titik tertentu Anda menulis ulang halaman HTML Anda untuk hanya membawa tautan yang cantik, seperti yang diuraikan oleh tipuan . Sementara itu, Anda masih akan menerima permintaan untuk jalur lama , terkadang bahkan dari bookmark. Sebagai solusinya , Anda dapat melakukan ping-pong browser untuk menampilkan / membuat URL baru.

    Trik umum ini melibatkan pengiriman 30x / Lokasi redirect setiap kali URL yang masuk mengikuti skema penamaan yang usang / jelek. Browser kemudian akan me - rerequest URL baru / cantik, yang kemudian ditulis ulang (hanya secara internal) ke lokasi asli atau baru.

     # redirect browser for old/ugly incoming paths
     RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]
    
     # internally remap already-pretty incoming request
     RewriteRule ^teams$ teams.php        [QSA,END]
    

    Perhatikan bagaimana contoh ini hanya digunakan [END]alih-alih [L]untuk alternatif yang aman. Untuk versi Apache 2.2 yang lebih lama, Anda dapat menggunakan solusi lain, selain juga memetakan ulang parameter string kueri misalnya: Redirect URL jelek ke cantik, remap kembali ke jalur jelek, tanpa loop tak terbatas

  • Spasi dalam pola
    /this+that+

    Ini tidak cantik di bilah alamat browser, tetapi Anda dapat menggunakan spasi di URL. Untuk menulis ulang pola, gunakan \␣spasi backslash-escape . Lain-lain- "kutip seluruh pola atau substitusi:

     RewriteRule  "^this [\w ]+/(.*)$"  "index.php?id=$1"  [L]
    

    Klien membuat serial URL dengan +atau %20untuk spasi. Namun dalam RewriteRules mereka ditafsirkan dengan karakter literal untuk semua segmen jalur relatif.

Duplikat yang sering:

lazim .htaccessperangkap

Sekarang ambil ini dengan sebutir garam. Tidak setiap saran dapat digeneralisasi untuk semua konteks. Ini hanya ringkasan sederhana dari batu sandungan yang terkenal dan beberapa yang tidak terlihat:

  • Aktifkan mod_rewritedan.htaccess

    Untuk benar-benar menggunakan RewriteRules dalam file konfigurasi per-direktori, Anda harus:

    • Periksa apakah server Anda telah AllowOverride Alldiaktifkan . Kalau tidak, .htaccessarahan per-direktori Anda akan diabaikan, dan RewriteRules tidak akan berfungsi.

    • Jelas telah mod_rewritediaktifkan di httpd.confbagian modul Anda .

    • Tambahkan setiap daftar aturan dengan RewriteEngine Ondiam. Sementara mod_rewrite secara aktif aktif di dalam <VirtualHost>dan <Directory>bagian, file per-direktori .htaccessmemerlukannya secara individual dipanggil.

  • Garis miring ^/tidak akan cocok

    Anda seharusnya tidak memulai .htaccesspola RewriteRule Anda dengan ^/normal:

     RewriteRule ^/article/\d+$  …
                  ↑
    

    Ini sering terlihat di tutorial lama. Dan itu dulu benar untuk versi Apache 1.x kuno. Saat ini jalur permintaan sepenuhnya direktori-relatif nyaman di .htaccessRewriteRules. Biarkan saja yang memimpin /.

    · Perhatikan bahwa slash utama masih benar di <VirtualHost>beberapa bagian. Itulah sebabnya Anda sering melihatnya ^/?dipilih untuk paritas aturan.
    · Atau saat menggunakan RewriteCond %{REQUEST_URI}kamu akan tetap cocok untuk seorang pemimpin /.
    · Lihat juga Webmaster.SE: Kapan garis miring (/) diperlukan dalam pola mod_rewrite?

  • <IfModule *> pembungkus hilang!

    Anda mungkin pernah melihat ini dalam banyak contoh:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • Itu memang masuk akal di <VirtualHost>bagian - jika itu dikombinasikan dengan opsi mundur lain, seperti ScriptAliasMatch. (Tapi tidak ada yang pernah melakukan itu).
    • Dan itu biasanya didistribusikan untuk pengaturan standar .htaccessdengan banyak proyek sumber terbuka. Itu hanya dimaksudkan sebagai mundur, dan menjaga URL "jelek" berfungsi sebagai default.

    Namun Anda tidak ingin itu biasanya di Anda sendiri.htaccess file .

    • Pertama, mod_rewrite tidak melepaskan secara acak. (Jika ya, Anda akan memiliki masalah yang lebih besar).
    • Jika benar-benar dinonaktifkan, RewriteRules Anda tetap tidak akan berfungsi.
    • Ini dimaksudkan untuk mencegah 500kesalahan HTTP . Apa yang biasanya dicapai adalah menghias pengguna Anda dengan 404kesalahan HTTP . (Tidak terlalu banyak ramah pengguna jika Anda memikirkannya.)
    • Praktis itu hanya menekan entri log yang lebih berguna, atau surat pemberitahuan server. Anda akan menjadi tidak tahu mengapa RewriteRules Anda tidak pernah berfungsi.

    Apa yang tampaknya memikat sebagai perlindungan menyeluruh, sering kali ternyata menjadi hambatan dalam praktik.

  • Jangan gunakan RewriteBase kecuali diperlukan

    Banyak contoh salin + tempel mengandung RewriteBase /arahan. Yang kebetulan merupakan default implisit. Jadi Anda tidak benar-benar membutuhkan ini. Ini merupakan solusi untuk skema penulisan ulang VirtualHost yang mewah, dan jalur DOCUMENT_ROOT yang disalahgunakan untuk beberapa host bersama.

    Masuk akal untuk digunakan dengan masing-masing aplikasi web di subdirektori yang lebih dalam. Ini dapat mempersingkat pola RewriteRule dalam kasus seperti itu. Secara umum yang terbaik adalah memilih penentu lintasan relatif dalam set aturan per-direktori.

    Lihat juga Bagaimana cara kerja RewriteBase di .htaccess

  • Nonaktifkan MultiViewssaat jalur virtual tumpang tindih

    Penulisan ulang URL terutama digunakan untuk mendukung jalur masuk virtual . Umumnya Anda hanya memiliki satu naskah operator ( index.php) atau penangan beberapa individu ( articles.php, blog.php, wiki.php, ...). Yang terakhir mungkin berbenturan dengan jalur RewriteRule virtual serupa.

    Permintaan /article/123misalnya dapat dipetakan ke article.phpdengan /123PATH_INFO secara implisit. Anda harus menjaga aturan Anda dengan RewriteCond !-f+ biasa !-d, dan / atau menonaktifkan dukungan PATH_INFO, atau mungkin hanya menonaktifkan Options -MultiViews.

    Yang tidak berarti Anda harus selalu melakukannya . Negosiasi konten hanyalah otomatisme untuk sumber daya virtual.

  • Memesan itu penting

    Lihat Segala sesuatu yang Anda ingin tahu tentang mod_rewrite jika Anda belum melakukannya. Menggabungkan beberapa RewriteRules sering menyebabkan interaksi. Ini bukan sesuatu untuk mencegah kebiasaan per [L]bendera, tetapi sebuah skema yang akan Anda terima setelah berpengalaman. Anda bisa kembali menulis ulang jalur virtual dari satu aturan ke aturan lain, hingga mencapai target handler yang sebenarnya.

    Tetap Anda sering ingin memiliki aturan yang paling spesifik ( /forum/…pola string tetap , atau placeholder yang lebih ketat [^/.]+) di aturan awal . Aturan slurp-all generik ( .*) lebih baik diserahkan kepada yang kemudian . (Pengecualian adalah RewriteCond -f/-dpelindung sebagai blok utama.)

  • Lembar gaya dan gambar berhenti berfungsi

    Saat Anda memperkenalkan struktur direktori virtual, /blog/article/123ini memengaruhi referensi sumber daya relatif dalam HTML (seperti <img src=mouse.png>). Yang bisa diselesaikan dengan:

    • Hanya menggunakan referensi mutlak server href="https://stackoverflow.com/old.html"atausrc="/logo.png"
    • Seringkali hanya dengan menambahkan <base href="https://stackoverflow.com/index">ke <head>bagian HTML Anda . Ini secara implisit menolak referensi relatif ke apa yang sebelumnya.

    Anda juga dapat membuat RewriteRules lebih lanjut untuk rebind .cssatau .pngpath ke lokasi aslinya. Tapi itu tidak dibutuhkan, atau menimbulkan pengalihan tambahan dan menghambat caching.

    Lihat juga: CSS, JS dan gambar tidak ditampilkan dengan url cantik

  • RewriteConds cukup sembunyikan satu RewriteRule

    Salah tafsir yang umum adalah bahwa RewriteCond memblokir beberapa RewriteRules (karena semuanya diatur secara visual bersama):

     RewriteCond %{SERVER_NAME} localhost
     RewriteRule ^secret  admin/tools.php
     RewriteRule ^hidden  sqladmin.cgi
    

    Yang tidak sesuai standar. Anda dapat rantai mereka menggunakan [S=2]bendera. Jika tidak, Anda harus mengulanginya. Meskipun terkadang Anda dapat membuat aturan utama "terbalik" untuk [AKHIR] proses penulisan ulang lebih awal.

  • QUERY_STRING dikecualikan dari RewriteRules

    Anda tidak dapat mencocokkan RewriteRule index.php\?x=y, karena mod_rewrite membandingkan hanya terhadap jalur relatif per default. Namun Anda dapat mencocokkannya secara terpisah melalui:

     RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
     RewriteRule ^add/(.+)$  add/%1/$1  # ←──﹪₁──┘
    

    Lihat juga Bagaimana saya bisa mencocokkan variabel string kueri dengan mod_rewrite?

  • .htaccess vs. <VirtualHost>

    Jika Anda menggunakan RewriteRules dalam file konfigurasi per-direktori, maka khawatir tentang kinerja regex tidak ada gunanya. Apache mempertahankan pola PCRE yang dikompilasi lebih lama dari proses PHP dengan kerangka kerja routing yang umum. Untuk situs dengan lalu lintas tinggi, Anda harus mempertimbangkan untuk memindahkan aturan ke konfigurasi server vhost, begitu mereka telah diuji pertempuran.

    Dalam hal ini, lebih suka ^/?awalan pemisah direktori yang di -pilih . Ini memungkinkan untuk memindahkan RewriteRules secara bebas antara PerDir dan file konfigurasi server.

  • Kapan pun sesuatu tidak bekerja

    Jangan khawatir.

    • Bandingkan access.logdanerror.log

      Seringkali Anda dapat mengetahui bagaimana Aturan Rewrite berlaku tidak adil hanya dengan melihat Anda error.logdanaccess.log . Korelasikan waktu akses untuk melihat jalur permintaan mana yang awalnya masuk, dan jalur / file mana yang tidak dapat diselesaikan oleh Apache (kesalahan 404/500).

      Ini tidak memberi tahu Anda siapa RewriteRule yang menjadi biang keladinya. Tapi jalan terakhir yang tidak dapat diakses seperti /docroot/21-.itle?index.phpmungkin memberikan tempat untuk memeriksa lebih lanjut. Atau nonaktifkan aturan hingga Anda mendapatkan beberapa jalur yang dapat diprediksi.

    • Aktifkan RewriteLog

      Lihat Apache RewriteLog docs. Untuk debugging Anda dapat mengaktifkannya di bagian vhost:

      # Apache 2.2
      RewriteLogLevel 5
      RewriteLog /tmp/rewrite.log
      
      # Apache 2.4
      LogLevel alert rewrite:trace5
      #ErrorLog /tmp/rewrite.log
      

      Itu menghasilkan ringkasan terperinci tentang bagaimana jalur permintaan yang masuk dimodifikasi oleh setiap aturan:

      [..] applying pattern '^test_.*$' to uri 'index.php'
      [..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
      [..] applying pattern '^index\.php$' to uri 'index.php'
      

      Yang membantu untuk mempersempit aturan terlalu umum dan regex kecelakaan.

      Lihat juga:
      · .htaccess tidak berfungsi (mod_rewrite)
      · Kiat untuk debugging .htaccess aturan penulisan ulang

    • Sebelum mengajukan pertanyaan Anda sendiri

      Seperti yang Anda ketahui, Stack Overflow sangat cocok untuk mengajukan pertanyaan pada mod_rewrite. Jadikan sesuai topik dengan memasukkan penelitian dan upaya sebelumnya (hindari jawaban yang berlebihan), tunjukkan dasar pemahaman, dan:

      • Sertakan contoh lengkap dari URL input, jalur target yang ditulis ulang secara salah, struktur direktori Anda yang sebenarnya.
      • Set RewriteRule lengkap, tetapi juga memilih yang dianggap rusak.
      • Versi Apache dan PHP, tipe OS, sistem file, DOCUMENT_ROOT, dan $_SERVERlingkungan PHP jika itu tentang ketidakcocokan parameter.
      • Kutipan dari Anda access.logdan error.loguntuk memverifikasi apa aturan yang ada diselesaikan untuk. Lebih baik lagi, rewrite.logringkasan.

      Ini menjaring jawaban yang lebih cepat dan lebih tepat, dan membuatnya lebih bermanfaat bagi orang lain.

  • Beri komentar .htaccess

    Jika Anda menyalin contoh dari suatu tempat, berhati-hatilah untuk memasukkan a # comment and origin link. Sementara itu hanya perilaku buruk untuk menghilangkan atribusi, itu sering benar-benar menyakitkan pemeliharaan nanti. Dokumentasikan kode atau sumber tutorial apa pun. Khususnya saat tidak berversi Anda harus lebih tertarik untuk tidak memperlakukan mereka seperti kotak hitam ajaib.

  • Ini bukan "SEO" -URLs

    Penafian: Hanya kencing kesayangan. Anda sering mendengar skema penulisan ulang URL yang cantik yang disebut tautan "SEO" atau semacamnya. Meskipun ini berguna untuk contoh-contoh googling, ini adalah istilah yang salah tanggal.

    Tidak ada mesin pencari modern yang benar-benar terganggu oleh .htmldan .phpdi segmen jalur, atau ?id=123string kueri dalam hal ini. Mesin pencari lama, seperti AltaVista, melakukannya menghindari merayapi situs web dengan jalur akses yang berpotensi ambigius. Perayap modern bahkan sering mendambakan sumber daya web yang dalam.

    Apa yang "cantik" URL harus secara konseptual digunakan untuk membuat situs web ramah pengguna .

    1. Memiliki skema sumber daya yang mudah dibaca dan jelas.
    2. Memastikan URL berumur panjang (AKA permalinks ).
    3. Memberikan kemampuan menemukan melalui /common/tree/nesting.

    Namun jangan mengorbankan persyaratan unik untuk konformisme.

Alat

Ada berbagai alat online untuk menghasilkan RewriteRules untuk sebagian besar URL GET-parameterish:

Sebagian besar hanya menampilkan [^/]+penampung generik, tetapi kemungkinan cukup untuk situs sepele.

mario
sumber
Masih perlu menulis ulang, lebih banyak tautan, dan banyak subjudul yang agak menjengkelkan. Ada beberapa tumpang tindih dengan jawaban lain di sini, jadi mungkin bisa ditebang. Ini terutama tentang contoh visual, dan daftar gotcha yang umum.
mario
3
Tidak melihat keindahan jawaban untuk waktu yang lama! Mata saya bersinar saat saya membacanya. Tolong jangan berhenti memposting jawaban seperti itu :)
Rizier123
1
Pos luar biasa. Membuat saya memahami konsep dasar mod_rewrite dengan sangat cepat!
semilir
6

Alternatif untuk mod_rewrite

Banyak skema URL virtual dasar dapat dicapai tanpa menggunakan RewriteRules. Apache memungkinkan skrip PHP dipanggil tanpa .phpekstensi, dan dengan PATH_INFOargumen virtual .

  1. Gunakan PATH_INFO , Luke

    Saat AcceptPathInfo Onini sering diaktifkan secara default. Yang pada dasarnya memungkinkan .phpdan URL sumber daya lainnya untuk membawa argumen virtual:

    http://example.com/script.php/virtual/path
    

    Sekarang ini /virtual/pathmuncul di PHP sebagai$_SERVER["PATH_INFO"] tempat Anda dapat menangani argumen tambahan apa pun yang Anda suka.

    Hal ini tidak nyaman seperti memiliki Apache segmen jalan input terpisah ke dalam $1, $2, $3dan melewati mereka sebagai berbeda $_GETvariabel untuk PHP. Ini hanya meniru "URL cantik" dengan sedikit upaya konfigurasi.

  2. Aktifkan MultiViews untuk menyembunyikan .phpekstensi

    Opsi paling sederhana untuk juga menghindari .php"ekstensi file" di URL adalah memungkinkan:

    Options +MultiViews
    

    Ini membuat Apache memilih article.phppermintaan HTTP pada /articlekarena nama dasarnya yang cocok. Dan ini bekerja dengan baik bersama dengan fitur PATH_INFO yang disebutkan di atas. Jadi Anda bisa menggunakan URL sepertihttp://example.com/article/virtual/title . Yang masuk akal jika Anda memiliki aplikasi web tradisional dengan beberapa poin / skrip permohonan PHP.

    Perhatikan bahwa MultiViews memiliki tujuan yang berbeda / lebih luas. Ini menimbulkan penalti kinerja yang sangat kecil , karena Apache selalu mencari file lain dengan nama dasar yang cocok. Ini benar-benar dimaksudkan untuk Content-Negosiasi , sehingga browser menerima alternatif terbaik di antara sumber daya yang tersedia (seperti article.en.php, article.fr.php, article.jp.mp4).

  3. SetType atau SetHandler untuk .phpskrip tanpa ekstensi

    Pendekatan yang lebih terarah untuk menghindari membawa .phpsufiks dalam URL adalah mengonfigurasi PHP handler untuk skema file lainnya. Opsi paling sederhana adalah mengganti tipe MIME / handler default melalui .htaccess:

    DefaultType application/x-httpd-php
    

    Dengan cara ini Anda bisa mengganti nama article.phpskrip Anda menjadi adil article(tanpa ekstensi), tetapi masih memprosesnya sebagai skrip PHP.

    Sekarang ini dapat memiliki beberapa implikasi keamanan dan kinerja, karena semua file tanpa ekstensi akan disalurkan melalui PHP sekarang. Karenanya, Anda dapat mengatur perilaku ini sebagai alternatif untuk file individual saja:

    <Files article>
      SetHandler application/x-httpd-php
      # or SetType 
    </Files>
    

    Ini agak tergantung pada pengaturan server Anda dan PHP SAPI yang digunakan. Alternatif umum termasuk ForceType application/x-httpd-phpatau AddHandler php5-script.

    Sekali lagi perhatikan bahwa pengaturan tersebut menyebar dari satu .htaccesske subfolder. Anda harus selalu menonaktifkan eksekusi skrip ( SetHandler Nonedan Options -Execatau php_flag engine offdll.) Untuk sumber daya statis, dan mengunggah / direktori dll.

  4. Skema penulisan ulang Apache lainnya

    Di antara banyak pilihannya, Apache menyediakan mod_aliasfitur - yang kadang-kadang berfungsi sama baiknya dengan mod_rewriteRewriteRules. Perhatikan bahwa sebagian besar dari mereka harus diatur dalam suatu <VirtualHost>bagian, tidak dalam .htaccessfile konfigurasi per-direktori .

    • ScriptAliasMatchterutama untuk skrip CGI, tetapi juga harus berfungsi untuk PHP. Ini memungkinkan regexps sama seperti apa pun RewriteRule. Bahkan itu mungkin opsi paling kuat untuk mengkonfigurasi pengontrol depan catch-all.

    • Dan polos Aliasmembantu dengan beberapa skema penulisan ulang sederhana juga.

    • Bahkan ErrorDocumentarahan sederhana dapat digunakan untuk membiarkan skrip PHP menangani jalur virtual. Perhatikan bahwa ini adalah solusi kludgy, tetapi melarang permintaan GET, dan membanjiri error.log menurut definisi.

    Lihat http://httpd.apache.org/docs/2.2/urlmapping.html untuk tips lebih lanjut.

mario
sumber