Referans: mod_rewrite, URL yeniden yazma ve “güzel bağlantılar” açıkladı


142

"Güzel bağlantılar" sıklıkla talep edilen bir konudur, ancak nadiren tam olarak açıklanmaktadır. mod_rewrite "güzel bağlantılar" yapmanın bir yoludur, ancak karmaşıktır ve sözdizimi çok kısa, grok yapmak zordur ve belgeler HTTP'de belirli bir yeterlilik seviyesini üstlenir. Birisi "güzel bağlantılar" nasıl çalışır ve mod_rewrite bunları oluşturmak için nasıl kullanılabilir basit terimlerle açıklayabilir?

Diğer yaygın adlar, takma adlar, temiz URL'ler için terimler: RESTful URL'ler, kullanıcı dostu URL'ler, SEO dostu URL'ler, gizli ve MVC URL'leri (muhtemelen yanlış adlandırma)


2
Slug veya Slugging, güzel URL'ler için başka bir yaygın takma ad / terimdir.
Mike B

2
@Mike Sort of, ancak sümüklü böcek genellikle güzel URL'lerin bir parçasıdır . Örneğin, bir makalenin başlığı, daha sonra o makalenin tanımlayıcısı olarak işlev gören URL dostu bir forma dönüştürüldüğünde bir bilgi, oldukça özeldir. Yani reference-mod-rewrite-url-rewriting-explainedsalyangozdur olan /questions/20563772/reference-mod-rewrite-url-rewriting-explainedoldukça URL'dir.
deceze

2
Bence .htaccessve mod-rewriteetiketleri, düzenli olarak sorulanların çoğunu kapsadığı için bu soruya bir bağlantı içerecek şekilde güncellenmelidir. Düşünceler?
Mike Rockétt

Yanıtlar:


110

Hangi mod_rewrite işlevini anlamak için önce bir web sunucusunun nasıl çalıştığını anlamanız gerekir. Bir web sunucusu HTTP isteklerine yanıt verir . En temel düzeydeki bir HTTP isteği şöyle görünür:

GET /foo/bar.html HTTP/1.1

Bu, bir tarayıcıdan URL'yi isteyen bir web sunucusuna basit bir istektir /foo/bar.html. Bir dosya istemediğini , sadece rastgele bir URL istediğini vurgulamak önemlidir . İstek ayrıca şöyle görünebilir:

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

Bu, bir URL için geçerli bir istektir ve dosyalar ile hiçbir ilgisi yoktur.

Web sunucusu, bir bağlantı noktasını dinleyen, o bağlantı noktasına gelen HTTP isteklerini kabul eden ve yanıt veren bir uygulamadır. Bir web sunucusu, herhangi bir isteğe uygun / herhangi bir şekilde yanıt verecek şekilde yapılandırdığınız herhangi bir isteğe yanıt vermekte tamamen serbesttir. Bu yanıt bir dosya değil, herhangi bir diskteki fiziksel dosyalarla ilgisi olan veya olmayan bir HTTP yanıtıdır . Bir web sunucusunun Apache olması gerekmez, hepsi sadece sürekli çalışan ve HTTP isteklerine yanıt veren bir bağlantı noktasına bağlı programlar olan birçok web sunucusu vardır. Birini kendiniz yazabilirsiniz. Bu paragrafın amacı, URL'lerin doğrudan dosyalara eşit olduğu ve gerçekten anlaşılması gereken herhangi bir kavramdan boşanmaktır. :)

Çoğu web sunucusunun varsayılan yapılandırması, sabit diskteki URL ile eşleşen bir dosya aramaktır. Eğer belge kök sunucusu olarak ayarlanır, diyelim ki, /var/wwwbu dosya olup olmadığını görünebilir /var/www/foo/bar.htmlvarsa ve o kadar eğer hizmet vermektedir. Dosya uçları ".php" Eğer PHP tercüman çağırmak ve edecek ardından sonuç döndürüyor. Tüm bu ilişki tamamen yapılandırılabilir; bir dosyanın web sunucusunun PHP yorumlayıcısı aracılığıyla çalıştırması için ".php" ile bitmesi gerekmez ve URL'nin bir şey olması için diskteki belirli bir dosyayla eşleşmesi gerekmez.

mod_rewrite, dahili istek işlemeyi yeniden yazmanın bir yoludur . Web sunucusu URL için bir istek aldığında /foo/barşunları yapabilirsiniz yeniden eşleştirebilmemizi diskteki bir dosyaya arayacaktır web sunucusu önce başka bir şeye o URL'yi. Basit örnek:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

Bu kural, bir istek "/ foo / bar" ile eşleştiğinde bunu "/ foo / baz" olarak yeniden yazar. Bu talep daha sonra /foo/baztalep edilmiş gibi ele alınacaktır . Bu, çeşitli efektler için kullanılabilir, örneğin:

RewriteRule (.*) $1.html

Bu kural bir şeyle ( .*) eşleşir ve onu yakalar ( (..)), ardından ".html" eklemek için yeniden yazar. Başka bir deyişle, /foo/baristenen URL olsaydı , istenmiş gibi işlenir /foo/bar.html. Normal ifade eşleştirme, yakalama ve değiştirme hakkında daha fazla bilgi için http://regular-expressions.info adresine bakın .

Sık karşılaşılan başka bir kural şudur:

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

Bu, yine herhangi bir şeyle eşleşir ve urlquery parametresine eklenen orijinal olarak istenen URL ile index.php dosyasına yeniden yazar . Yani, gelen tüm istekler için, index.php dosyası yürütülür ve bu dosya orijinal isteğe erişebilir $_GET['url'], böylece onunla istediği her şeyi yapabilir.

Öncelikle bu yeniden yazma kurallarını web sunucusu yapılandırma dosyanıza koyarsınız . Apache ayrıca * bunları .htaccessbelge kökünüzde (yani .php dosyalarınızın yanında) adlı bir dosyaya koymanıza izin verir .

* Eğer birincil Apache yapılandırma dosyası tarafından izin; isteğe bağlıdır, ancak genellikle etkindir.

Mod_rewrite'ı gelmez Ne değil yapmak

mod_rewrite, tüm URL'lerinizi sihirli bir şekilde "güzel" yapmaz. Bu yaygın bir yanlış anlamadır. Web sitenizde bu bağlantı varsa:

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

mod_rewrite'ın bunu güzelleştirmek için yapabileceği hiçbir şey yok. Bunu güzel bir bağlantı haline getirmek için yapmanız gerekenler:

  1. Bağlantıyı güzel bir bağlantıyla değiştirin:

    <a href="https://stackoverflow.com/my/pretty/link">
    
  2. /my/pretty/linkYukarıda açıklanan yöntemlerden birini kullanarak URL isteğini işlemek için sunucuda mod_rewrite komutunu kullanın .

( mod_substituteGiden HTML sayfalarını ve içerdiği bağlantıları dönüştürmek için birlikte kullanılabilir . Yine de bu genellikle HTML kaynaklarınızı güncellemekten daha fazla çaba gerektirir.)

Çok sayıda yeniden yazma, zincirleme isteklerini tamamen farklı bir hizmete veya makineye proxy gönderme, belirli HTTP durum kodlarını yanıt olarak döndürme, yeniden yönlendirme istekleri vb. temel HTTP istek-yanıt mekanizmasını anlarsanız çok iyi. O mu değil otomatik bağlantıları oldukça olun.

Olası tüm bayraklar ve seçenekler için resmi belgelere bakın .


6
Belki bir dağıtım programına yeniden yazmanın tercih edilen yolu olarak 2.2.16 sürümünde sunulan FallbackResource yönergesinden bahsedin .
Darsstar

78

Deceze'nin cevabını genişletmek için birkaç örnek ve diğer mod_rewrite işlevlerinin açıklamasını istedim.

Örnekler aşağıda Bütün bunlar zaten dahil olduğu düşünülerek RewriteEngine Onsizin de .htaccessdosyaya.

Yeniden Yazma Örneği

Bu örneği ele alalım:

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

Kural 4 bölüme ayrılmıştır:

  1. RewriteRule - yeniden yazma kuralını başlatır
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - Buna desen denir, ancak bunu kuralın sol tarafı olarak anlatacağım - yeniden yazmak istediğiniz şey
  3. blog/index.php?id=$1&title=$2 - değiştirme veya yeniden yazma kuralının sağ tarafı olarak adlandırılır - yeniden yazmak istediğiniz şey
  4. [NC,L,QSA] daha sonra açıklayacağım virgülle ayrılmış yeniden yazma kuralı için bayraklardır

Yukarıdaki yeniden yazma, benzer bir şeye bağlantı vermenize izin verir /blog/1/foo/ve aslında yüklenir /blog/index.php?id=1&title=foo.

Kuralın sol tarafı

  • ^sayfa adının başlangıcını gösterir - böylece yeniden yazılır example.com/blog/...ancakexample.com/foo/blog/...
  • Her (…)parantez kümesi , kuralın sağ tarafında değişken olarak yakalayabileceğimiz normal bir ifadeyi temsil eder. Bu örnekte:
    • İlk parantez grubu - ([0-9]+)- en az 1 karakter uzunluğunda ve yalnızca sayısal değerlerle (yani 0-9) bir dizeyle eşleşir. Buna $1kuralın sağ tarafında başvurulabilir
    • İkinci parantez kümesi, en az 1 karakter uzunluğunda bir dizeyle eşleşir, yalnızca alfasayısal karakterler (AZ, az veya 0-9) veya -veya +(not +, kaçmadan ters eğik çizgi ile kaçarsa, bu normal ifade olarak yürütülür) tekrarlama karakteri ). Buna $2kuralın sağ tarafında başvurulabilir
  • ?Yukarıdaki karakterim çok bu durumda, isteğe bağlıdır araç hem /blog/1/foo/ve /blog/1/fooaynı yere yeniden yazmak istiyorum
  • $ bunun eşleştirmek istediğimiz dizenin sonu olduğunu belirtir

Bayraklar

Bunlar, belirli koşulları belirtmek için yeniden yazma kuralınızın sonuna köşeli parantez içinde eklenen seçeneklerdir. Yine, belgelerde okuyabileceğiniz birçok farklı bayrak var , ancak daha yaygın bayraklardan bazılarını inceleyeceğim:

NC

Büyük / küçük harf yok bayrağı, yeniden yazma kuralının büyük / küçük harfe duyarlı olmadığı anlamına gelir; bu nedenle yukarıdaki örnek kural için bu /blog/1/foo/ve /BLOG/1/foo/(veya bunun herhangi bir varyasyonu) eşleşeceği anlamına gelir.

L

Son bayrak bunun işlenmesi gereken son kural olduğunu gösterir. Bu, yalnızca ve bu kural eşleşirse, geçerli yeniden yazma işleminde başka kuralların değerlendirilmeyeceği anlamına gelir. Kural eşleşmezse, diğer tüm kurallar her zamanki gibi denenecektir. LBayrağı ayarlamazsanız, aşağıdaki tüm kurallar daha sonra yeniden yazılan URL'ye uygulanır .

END

Apache 2.4'ten beri [END]bayrağı da kullanabilirsiniz . Onunla eşleşen bir kural, diğer takma ad / yeniden yazma işlemlerini tamamen sonlandıracaktır. ( [L]Bayrak çoğu zaman ikinci bir turu tetikleyebilirken, örneğin alt dizinlere yeniden girerken veya dizinlerden çıkarken.)

QSA

Sorgu dizesi ekleme bayrağı, orijinal get parametrelerine eklenecek belirtilen URL'ye ekstra değişkenler iletmemize olanak tanır. Örneğimiz için bu, benzer bir şeyin /blog/1/foo/?comments=15yükleneceği anlamına gelir/blog/index.php?id=1&title=foo&comments=15

R

Bu bayrak yukarıdaki örnekte kullandığım değil, bahsetmeye değer olduğunu düşündüğüm bayrak. Bu, bir durum kodu (ör. R=301) Ekleme seçeneğiyle bir http yönlendirmesi belirtmenize olanak tanır . Örneğin, / myblog / dizinine / blog / dizinine 301 yönlendirmesi yapmak isterseniz, şöyle bir kural yazmanız yeterlidir:

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

Koşulları Yeniden Yaz

Yeniden yazma koşulları , yeniden yazma işlemlerini daha da güçlü hale getirir ve daha özel durumlar için yeniden yazma işlemleri belirlemenizi sağlar. Belgelerde okuyabileceğiniz birçok koşul var , ancak birkaç yaygın örneğe değineceğim ve açıklayacağım:

# 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]

Bu, alan adınızın başına www.(zaten yoksa) başlayacak ve 301 yönlendirmesi gerçekleştirecek çok yaygın bir uygulamadır . Örneğin, yüklemeniz http://example.com/blog/sizihttp://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]

Bu biraz daha az yaygındır, ancak dosya adı sunucuda var olan bir dizin veya dosyaysa yürütülmeyen bir kurala iyi bir örnektir.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] yalnızca jpg, jpeg, gif veya png dosya uzantısına sahip dosyalar için yeniden yazma işlemini yürütür (büyük / küçük harf duyarsız).
  • %{REQUEST_FILENAME} !-f dosyanın geçerli sunucuda olup olmadığını kontrol eder ve yeniden yazma işlemini yalnızca
  • %{REQUEST_FILENAME} !-d dosyanın geçerli sunucuda olup olmadığını kontrol eder ve yeniden yazma işlemini yalnızca
  • Yeniden yazma aynı dosyayı başka bir etki alanına yüklemeye çalışır

39

Referanslar

Stack Overflow, başlamak için başka birçok harika kaynağa sahiptir:

Ve yeni gelen regex bile göz ardı ediyor:

Sık kullanılan yer tutucular

  • .*boş bir dizeyle bile her şeyle eşleşir. Bu kalıbı her yerde kullanmak istemezsiniz, ancak genellikle son geri dönüş kuralında kullanabilirsiniz.
  • [^/]+yol bölümleri için daha sık kullanılır. Eğik çizgiden başka bir şeyle uyuşmuyor.
  • \d+ yalnızca sayısal dizelerle eşleşir.
  • \w+alfasayısal karakterlerle eşleşir. Temelde kısaca [A-Za-z0-9_].
  • [\w\-]+harfler, rakamlar, tire ve çizgi kullanarak "slug" tarzı yol segmentleri için- _
  • [\w\-.,]+nokta ve virgül ekler. Sınıflarda kaçan bir \-çizgi tercih […]edin.
  • \.anlamına gelir. Aksi takdirde .dışında bir […]herhangi bir sembolün tutucudur.

Bu yer tutucuların her biri genellikle (…)yakalama grubu olarak parantez içine alınır . Ve tüm desen genellikle ^………$başlangıç ​​+ bitiş işaretleyicilerinde. "Kalıplar" dan alıntı yapmak isteğe bağlıdır.

RewriteRules

Aşağıdaki örnekler, PHP merkezli ve biraz daha artımlı, benzer durumlar için daha kolay adapte edilebilir. Bunlar sadece özetlerdir, genellikle daha fazla varyasyona veya ayrıntılı Soru ve Cevaplara bağlanır.

  • Statik haritalama
    /contact,/about

    Birkaç sayfa adını dahili dosya düzenlerine kısaltmak en basit yöntemdir:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • Sayısal tanımlayıcılar
    /object/123

    http://example.com/article/531Mevcut PHP betikleri gibi kısayollarla tanışmak da kolaydır. Sayısal yer tutucu bir $_GETparametreye yeniden eşlenebilir :

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
     #                      └───────────────────────────┘
    
  • Slug tarzı yer tutucular
    /article/with-some-title-slug

    Yer /article/title-stringtutuculara izin vermek için bu kuralı kolayca genişletebilirsiniz :

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

    Komut dosyanızın bu başlıkları veritabanı kimlikleriyle eşleştirebilmesi (veya uyarlanması) gerektiğini unutmayın . RewriteRules tek başına ince havadan bilgi oluşturamaz veya tahmin edemez.

  • Sayısal önekli sümüklü böcek
    /readable/123-plus-title

    Bu nedenle /article/529-title-slug, pratikte sıklıkla kullanılan karışık yollar görürsünüz :

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

    Artık title=$2kodunuzu geçmeyi atlayabilirsiniz , çünkü betiğiniz genellikle yine de veritabanı kimliğine dayanacaktır. -title-slugİsteğe bağlı URL dekorasyon haline gelmiştir.

  • Alternatif listelerle tekdüzelik
    /foo/… /bar/… /baz/…

    Birden çok sanal sayfa yolu için benzer kurallarınız varsa, bunları |alternatif listelerle eşleştirebilir ve sıkıştırabilirsiniz . Ve tekrar onları dahili GET parametrelerine yeniden atayın:

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

    RewriteRuleBu çok karmaşık hale gelirse onları ayrı ayrı silebilirsiniz.

  • İlgili URL'leri farklı arka uçlara gönderme
    /date/SWITCH/backend

    Alternatif listelerin daha pratik bir kullanımı, istek yollarının farklı komut dosyalarıyla eşleştirilmesidir. Örneğin, eski ve daha yeni bir web uygulaması için tarihlere dayalı tek tip URL'ler sağlamak için:

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

    Bu, 2009-2011 yayınlarını bir komut dosyasına ve diğer tüm yıllara dolaylı olarak başka bir işleyiciye hatırlar. Not Daha spesifik bir kural ilk gelen . Her komut dosyası farklı GET parametreleri kullanabilir.

  • /Yol eğik çizgileri dışındaki diğer sınırlayıcılar
    /user-123-name

    Sanal dizin yapısını taklit etmek için en sık RewriteRules'ü görürsünüz. Ama yaratıcı olmak zorunda değilsin. -Bölümleme veya yapı için kısa çizgiler de kullanabilirsiniz .

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

    Ayrıca ortak /wiki:section:Page_Nameşema için:

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

    Bazen arasında dönüşümlü olarak birbirini uygundur /-delimiters ve :ya .hatta aynı kuralda. Veya varyantları farklı komut dosyalarına eşlemek için tekrar iki RewriteRule'a sahip olun.

  • İsteğe bağlı eğik /çizgi
    /dir=/dir/

    Dizin tarzı yolları seçerken, bir final ile veya bir final olmadan bunu erişilebilir yapabilirsiniz /

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

    Şimdi bu ikisini de ele alıyor http://example.com/blog/123ve /blog/123/. Ve /?$yaklaşımın diğer RewriteRule'a eklenmesi kolaydır.

  • Sanal yollar için esnek segmentler
    .*/.*/.*/.*

    Karşılaşacağınız çoğu kural, kısıtlanmış bir /…/kaynak yolu segmentleri kümesini tek tek GET parametrelerine eşler. Ancak bazı komut dosyaları değişken sayıda seçeneği kullanır . Apache normal ifade motoru, rastgele sayıda isteğe bağlılaştırmaya izin vermez. Ancak bunu kolayca bir kural bloğuna genişletebilirsiniz:

     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
     #              └─────┴─────┴───────────────────┴────┴────┘
    

    En fazla beş yol parçasına ihtiyacınız varsa, bu şemayı beş kurala kopyalayın. Elbette [^/]+her biri daha spesifik bir yer tutucu kullanabilirsiniz . Burada sıralama, ikisi de örtüşmediği kadar önemli değildir. Bu yüzden ilk olarak en sık kullanılan yolları kullanmak iyidir.

    Alternatif olarak, PHP'nin dizi parametrelerini ?p[]=$1&p[]=$2&p[]=3burada sorgu dizesi aracılığıyla kullanabilirsiniz - eğer betiğiniz sadece önceden bölünmüşse. (Her şeyi yakalama kuralı kullanmak ve komut dosyasının kendisini segmentleri REQUEST_URI kapsamından genişletmesine izin vermek daha yaygın olsa da.)

    Ayrıca bkz: URL yolu segmentlerimi sorgu dizesi anahtar / değer çiftlerine nasıl dönüştürebilirim?

  • İsteğe bağlı segmentler
    prefix/opt?/.*

    Yaygın bir varyasyon, kural içinde isteğe bağlı öneklerin bulunmasıdır . Statik dizeleriniz veya etrafınızda daha kısıtlanmış yer tutucularınız varsa, bu genellikle mantıklıdır:

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

    Şimdi daha karmaşık desen , yakalamayan bir grubu (?:/([^/])+)?sarar ve isteğe bağlı hale getirir . İçerilen yer tutucu ikame kalıbı olur , ancak orta yol yoksa boş olur . (?:…))?([^/]+)$2/…/

  • Kalanları yakalayın
    /prefix/123-capture/…/*/…whatever…

    Daha önce de belirtildiği gibi, genellikle çok genel yeniden yazma kalıpları istemezsiniz. Bununla birlikte, statik ve spesifik karşılaştırmaları .*bazen ile birleştirmek mantıklıdır .

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

    Bu, herhangi bir optionalized /…/…/…arka yol parçaları. Hangi elbette onları ayırmak için taşıma komut dosyası gerektirir ve variabl-ify parametrelerin kendisi ( Web- "MVC" çerçeveleri ne yaptığı) ayıkladı .

  • Sondaki "uzantılar" dosyası
    /old/path.HTML

    URL'lerin gerçekte dosya uzantıları yoktur. Bu referansın tamamı bununla ilgilidir (= URL'ler sanal bir konumlandırıcıdır, doğrudan dosya sistemi görüntüsü olmak zorunda değildir). Eğer bir 1 vardı Ancak eğer: önce 1 dosya eşlemesi, sen yapabilirsiniz basit kurallar zanaat:

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

    Diğer yaygın kullanımlar, eski .htmlyolların daha yeni .phpişleyicilere yeniden eşlenmesi veya yalnızca dizin adlarının yalnızca tek tek (gerçek / gerçek) dosyalar için takma adıdır.

  • Ping-Pong (birlikte yönlendirir ve yeniden yazar)
    /ugly.html← →/pretty

    Yani bir noktada HTML sayfalarınızı deceze ile özetlendiği gibi sadece güzel bağlantılar taşımak için yeniden yazıyorsunuz . Bu arada , bazen yer işaretlerinden bile olsa eski yollar için istek alırsınız . Gibi geçici çözüm , sen / ekrana tarayıcılar pong-ping yeni URL'leri kurabilir.

    Bu yaygın hile, gelen bir URL eski / çirkin adlandırma düzenini izlediğinde 30x / Konum yönlendirmesi göndermeyi içerir . Tarayıcılar daha sonra orijinal / yeni konuma yeniden yazılan (yalnızca dahili olarak) yeni / güzel URL'yi yeniden isteyecektir .

     # 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]
    

    Bu örneğin güvenli bir şekilde değiştirmek [END]yerine nasıl kullandığını unutmayın [L]. Daha eski Apache 2.2 sürümleri için, sorgu dizesi parametrelerini yeniden eşlemenin yanı sıra diğer geçici çözümleri de kullanabilirsiniz: Çirkin URL'yi güzel URL'ye yeniden yönlendirin, sonsuz döngüler olmadan çirkin yola yeniden eşleyin

  • Desenlerdeki uzaylar
    /this+that+

    Tarayıcı adres çubuklarında o kadar da güzel değil , ancak URL'lerde boşluk kullanabilirsiniz. Yeniden yazma desenleri için ters eğik çizgiden kaçan \␣boşluklar kullanın . Başka sadece- "tüm desen veya ikame tırnak:

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

    İstemciler URL'leri boşluklarla +veya %20boşluklarla serileştirir . Yine de RewriteRules'te, tüm göreceli yol bölümleri için gerçek karakterler ile yorumlanırlar.

Sık kopyalar:

Yaygın .htaccesstuzaklar

Şimdi bunu bir tane tuzla al. Her tavsiye tüm bağlamlarda genelleştirilemez. Bu sadece iyi bilinen ve birkaç belirsiz engelin basit bir özetidir:

  • Etkinleştir mod_rewriteve.htaccess

    Gerçekten dizin başına yapılandırma dosyalarında RewriteRules kullanmak için:

    • Sunucunuzun AllowOverride Alletkin olup olmadığını kontrol edin . Aksi takdirde, dizin başına .htaccessyönergeleriniz yok sayılır ve RewriteRules çalışmaz.

    • Açıkçası var mod_rewriteetkin sizin de httpd.confmodüller bölümünde.

    • Her kural listesini RewriteEngine Onhareketsiz olarak kullanın. Mod_rewrite <VirtualHost>ve <Directory>bölümlerde dolaylı olarak etkin olsa da , dizin başına .htaccessdosyaların ayrı ayrı çağırılması gerekir.

  • Baştaki eğik çizgi ^/eşleşmiyor

    .htaccessRewriteRule kalıplarınızı ^/normal şekilde başlatmamalısınız :

     RewriteRule ^/article/\d+$  …
                  ↑
    

    Bu genellikle eski derslerde görülür. Eski Apache 1.x sürümleri için de doğruydu. Günümüzde istek yolları RewriteRules içinde tamamen dizine.htaccess göredir. Sadece öncüyü /dışarıda bırak .

    · Öndeki eğik çizginin yine de bazı <VirtualHost>bölümlerde doğru olduğunu unutmayın . Bu yüzden sık sık ^/?kural paritesi için isteğe bağlı olarak görüyorsunuz .
    · Ya da RewriteCond %{REQUEST_URI}bir lider kullanırken hala eşleşirsiniz /.
    · Ayrıca bkz. Webmaster.SE: Mod_rewrite desenlerinde başa eğik çizgi (/) ne zaman ihtiyaç duyulur?

  • <IfModule *> sarmalayıcılar başladı!

    Bunu muhtemelen birçok örnekte görmüşsünüzdür:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • O does içinde mantıklı <VirtualHost>bölümler - böyle ScriptAliasMatch gibi başka düşürme seçeneği ile birleştirildi eğer. (Ama bunu kimse yapmaz).
    • Ve genellikle .htaccessbirçok açık kaynaklı projeye sahip varsayılan kural kümeleri için dağıtılır . Orada sadece yedek olarak kullanılır ve "çirkin" URL'lerin varsayılan olarak çalışmasını sağlar.

    Ancak bunu genellikle kendi dosyalarınızda istemezsiniz.htaccess .

    • Birincisi, mod_rewrite rastgele ayrılmaz. (Eğer olsaydı, daha büyük sorunların olurdu).
    • Gerçekten devre dışı bırakıldıysa, RewriteRules'ünüz yine de çalışmaz.
    • HTTP 500hatalarını önlemek içindir . Genellikle elde ettiği şey, kullanıcılarınızı 404bunun yerine HTTP hatalarıyla bilgilendirmektir . (Düşünüyorsanız çok daha kullanıcı dostu değil.)
    • Pratik olarak sadece daha kullanışlı günlük girişlerini veya sunucu bildirim postalarını bastırır. Sen olurdu hiçbiri akıllıca sizin RewriteRules iş asla neden olarak.

    Genelleştirilmiş bir koruma olarak cazip gelen şey, genellikle pratikte bir engel haline gelir.

  • RewriteBaseGerekmedikçe kullanma

    Birçok kopyala + yapıştır örneği bir RewriteBase /yönerge içerir . Zaten örtük varsayılan da budur. Yani aslında buna ihtiyacınız yok. Süslü VirtualHost yeniden yazma şemaları ve bazı paylaşılan barındırıcılar için yanlış DOCUMENT_ROOT yolları için bir geçici çözümdür.

    Daha derin alt dizinlerde bireysel web uygulamalarıyla kullanmak mantıklıdır. Bu gibi durumlarda RewriteRule kalıplarını kısaltabilir. Genellikle dizin başına kural kümelerinde göreli yol belirteçlerini tercih etmek en iyisidir.

    Ayrıca bkz. RewriteBase .htaccess içinde nasıl çalışır

  • MultiViewsSanal yollar çakıştığında devre dışı bırak

    URL yeniden yazma esas olarak sanal gelen yolları desteklemek için kullanılır . Yaygın sadece tek hareket memuru komut dosyası (varsa index.php) ya da birkaç münferit işleyicileri ( articles.php, blog.php, wiki.php, ...). İkinci kudreti çatışma benzer sanal RewriteRule yolları ile.

    Talebi /article/123örneği eşlenebilmesi için article.phpbir ile /123örtülü PAT_INFO. Kurallarınızı o zaman ortak RewriteCond !-f+ ile korumanız !-dve / veya PATH_INFO desteğini devre dışı bırakmanız veya belki de devre dışı bırakmanız gerekir Options -MultiViews.

    Bu her zaman zorunda olmanız demek değildir . İçerik-Müzakere sadece sanal kaynaklar için bir otomatizmdir.

  • Sipariş önemlidir

    Görmek Henüz yapmadıysanız mod_rewrite hakkında bilmek istediğiniz her şeye . Birden çok Yeniden Yazma Kuralını birleştirmek genellikle etkileşime yol açar. Bu, [L]bayrak başına alışkanlık olarak önlenecek bir şey değil , bir kez ayetleneceğiniz bir şema. Sen edebilirsiniz yeniden yeniden yeniden yazma sanal yolları bir kural diğerine, gerçek bir hedef işleyicisi ulaşana kadar.

    Hala ediyorum çoğu zaman en belirli kurallar (sabit dize olmasını istediğiniz /forum/…desenleri veya daha kısıtlayıcı tutucuları [^/.]+olarak) erken kurallarda . Genel slurp-all kuralları ( .*) sonraki kurallara bırakılır . (Bir istisna, RewriteCond -f/-dbirincil blok olarak bir muhafızdır.)

  • Stil sayfaları ve görüntülerin çalışması durdu

    Sanal dizin yapılarını tanıttığınızda, /blog/article/123bu HTML'deki göreli kaynak başvurularını (örneğin <img src=mouse.png>) etkiler . Hangi ile çözülebilir:

    • Yalnızca sunucu mutlak başvuruları kullanarak href="https://stackoverflow.com/old.html" veyasrc="/logo.png"
    • Genellikle ekleyerek <base href="https://stackoverflow.com/index"> HTML <head>bölümünüze . Bu, daha öncekilere ilişkin göreceli referansları dolaylı olarak hatırlatır.

    Alternatif olarak yeniden hatırlatmak için başka RewriteRules oluşturabilirsiniz .css.png olarak, orijinal konumlarına veya yolları . Ancak bu hem gereksizdir hem de fazladan yönlendirmelere neden olur ve önbelleğe almayı engeller.

    Ayrıca bakınız: CSS, JS ve resimler güzel url ile görüntülenmiyor

  • RewriteConds yalnızca bir RewriteRule'u maskeliyor

    Yaygın bir yanlış yorumlama, bir RewriteCond'un birden fazla RewriteRule'u engellemesidir (çünkü görsel olarak birlikte düzenlenmiştir):

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

    Hangi varsayılan başına değil. Sen edebilirsiniz zincirleyin kullanarak[S=2] bayrağı. Yoksa onları tekrarlamanız gerekecek. Bazen yeniden yazma işlemini erken yapmak için "END" olarak "ters" bir birincil kural oluşturabilirsiniz.

  • QUERY_STRING, RewriteRules'ten muaf

    Sen maç olamaz RewriteRule index.php\?x=ymod_rewrite'ı varsayılan başına göreli yollar karşı sadece karşılaştırır çünkü. Bunları ayrı ayrı eşleştirebilirsiniz ancak:

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

    Ayrıca bkz. Sorgu dizesi değişkenlerini mod_rewrite ile nasıl eşleştirebilirim?

  • .htaccess vs. <VirtualHost>

    Bir dizin başına yapılandırma dosyasında RewriteRules kullanıyorsanız, normal ifade performansından endişe etmek anlamsızdır. Apache, derlenmiş PCRE modellerini ortak bir yönlendirme çerçevesine sahip bir PHP işleminden daha uzun süre korur. Yüksek trafikli siteler için, savaş testlerinden sonra kural kümelerini hayalet sunucu yapılandırmasına taşımayı düşünmelisiniz.

    Bu durumda, isteğe bağlı ^/?dizin ayırıcı önekini tercih edin . Bu, RewriteRules'ün PerDir ve sunucu yapılandırma dosyaları arasında serbestçe taşınmasına izin verir.

  • Bir şey işe yaramadığında

    Üzülme.

    • Karşılaştır access.logveerror.log

      Genellikle bir RewriteRule'ün sadece sizin error.logveaccess.log . Başlangıçta hangi istek yolunun geldiğini ve Apache'nin hangi yolu / dosyayı çözemediğini görmek için erişim sürelerini ilişkilendirin (hata 404/500).

      Bu size hangi RewriteRule'un suçlu olduğunu söylemez. Ancak, erişilemeyen son yollar /docroot/21-.itle?index.php, nerede daha fazla inceleme yapılacağını verebilir. Aksi takdirde, tahmin edilebilir bazı yollar elde edene kadar kuralları devre dışı bırakın.

    • Yeniden Yazmayı Etkinleştir

      Bkz. Apache RewriteLog belgeleri. Hata ayıklama için, vhost bölümlerinde etkinleştirebilirsiniz:

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

      Bu, gelen istek yollarının her kural tarafından nasıl değiştirildiğinin ayrıntılı bir özetini verir:

      [..] 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'
      

      Bu, aşırı genel kuralları daraltmaya ve aksiliklere neden olur.

      Ayrıca bkz:
      · .htaccess çalışmıyor (mod_rewrite)
      · Hata ayıklama ipuçları .htaccess yeniden yazma kuralları

    • Kendi sorunuzu sormadan önce

      Bildiğiniz gibi, Stack Overflow mod_rewrite hakkında soru sormak için çok uygundur. Onları konu haline getirin Önceden araştırma ve girişimler ekleyerek (gereksiz cevaplardan kaçının) , temelleri gösterin anlayış ve

      • Dahil tam giriş URL'lerin örnekler, falsly yeniden yazılmış hedef yolları, gerçek dizin yapısı.
      • Komple RewriteRule seti, aynı zamanda varsayılan kusurlu olanı tek tek belirler.
      • $_SERVERBir parametre uyuşmazlığıyla ilgili ise Apache ve PHP sürümleri, işletim sistemi türü, dosya sistemi, DOCUMENT_ROOT ve PHP ortamları.
      • Sizden bir alıntı access.logve error.logmevcut kuralların neyi çözdüğünü doğrulamak için. Daha da iyisi, bir rewrite.logözet.

      Bu, daha hızlı ve daha kesin cevaplar sağlar ve başkaları için daha kullanışlı hale getirir.

  • Yorum yapın .htaccess

    Örnekleri bir yerden kopyalarsanız, a # comment and origin link. Atıf atlamak sadece kötü bir davranış olsa da, genellikle daha sonra bakımdan zarar verir. Herhangi bir kodu veya eğitim kaynağını belgeleyin. Özellikle de açıkken, onlara sihirli kara kutular gibi davranmamaya daha çok ilgi duymalısınız.

  • "SEO" -URL değil

    Feragat: Sadece bir evcil hayvan huşu. Sıklıkla "SEO" bağlantıları olarak adlandırılan güzel URL yeniden yazma şemalarını duyarsınız. Bu, googling örnekleri için yararlı olsa da, tarihli bir yanlış adlandırmadır.

    Modern arama motorlarının hiçbiri gerçekten rahatsız olan .htmlve .phpyol kesimleri, ya da ?id=123bu konuda sorgu dizeleri. Böyle AltaVista olarak eski Arama motorları, yaptığımız potansiyel olarak kuşkulu erişim yolları ile web sitelerini tarayarak avoid. Modern tarayıcılar genellikle derin web kaynakları için bile özlem duyuyor.

    "Güzel" URL'lerin kavramsal olarak kullanılması gereken şey, web sitelerini kullanıcı dostu yapmaktır .

    1. Okunabilir ve açık kaynak planlarına sahip olmak.
    2. URL'lerin uzun ömürlü olmasını sağlamak (AKA kalıcı bağlantıları ).
    3. Aracılığıyla keşfedilebilirlik sağlama /common/tree/nesting.

    Ancak konformizm için benzersiz gerekliliklerden ödün vermeyin.

Araçlar

Çoğu GET parametresi URL'si için RewriteRules oluşturmak için çeşitli çevrimiçi araçlar vardır:

Çoğunlukla [^/]+genel yer tutucuları çıktılar , ancak önemsiz siteler için muhtemelen yeterli olur.


Yine de biraz yeniden yazılmaya, daha fazla bağlantıya ve birçok alt başlığa biraz iğrenç. Buradaki diğer cevaplarla bir miktar örtüşme var, bu yüzden belki de kesilebilir. Esas olarak görsel örnekler ve bu ortak yaka listesi ile ilgilidir.
mario

3
Uzun zamandır böyle bir cevap güzelliği görmedim! Ben okurken gözlerim parlıyor. Lütfen bu tür cevapları göndermeyi bırakmayın :)
Rizier123

1
Mükemmel gönderi. Mod_rewrite ile ilgili temel kavramları çok çabuk anlamamı sağladı!
Breez

6

Mod_rewrite Alternatifleri

RewriteRules kullanılmadan birçok temel sanal URL şeması elde edilebilir. Apache, PHP betiklerinin .phpuzantısız ve sanal bir PATH_INFOargümanla çağrılmasını sağlar .

  1. PATH_INFO kullanın , Luke

    Günümüzde AcceptPathInfo Ongenellikle varsayılan olarak etkindir. Temel olarak, .phpdiğer kaynak URL'lerinin sanal bir argüman taşımasına izin verir :

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

    Şimdi bu /virtual/pathPHP'de$_SERVER["PATH_INFO"] herhangi bir ekstra argümanları istediğiniz gibi ele nerede .

    Bu içine Apache'nin ayrı giriş yolu bölümlerine sahip olan olarak uygun değildir $1, $2, $3ve farklı olarak geçen $_GETPHP değişkenler. Yalnızca daha az yapılandırma çabasıyla "güzel URL'leri" taklit eder.

  2. Uzantıyı gizlemek için MultiViews'ı etkinleştirin.php

    .phpURL'lerde "dosya uzantılarından" kaçınmanın en basit yolu aşağıdakileri etkinleştirmektir:

    Options +MultiViews
    

    Bu, eşleşen taban adı nedeniyle article.phpHTTP istekleri için Apache /articleseçimine sahiptir. Bu, yukarıda belirtilen PATH_INFO özelliğiyle birlikte iyi çalışır. Böylece, aşağıdaki gibi URL'leri kullanabilirsiniz:http://example.com/article/virtual/title . Birden fazla PHP çağırma noktası / komut dosyası içeren geleneksel bir web uygulamanız varsa bu mantıklıdır.

    MultiViews'ın farklı / daha geniş bir amacı olduğunu unutmayın. Bu bir incurs çok küçük Apaçi hep eşleşen basenames ile diğer dosyalar için göründüğünden, performans kaybına. Aslında İçerik-Müzakere amaçlıdır , bu nedenle tarayıcılar mevcut kaynaklar ( article.en.php,, article.fr.phpgibi article.jp.mp4) arasında en iyi alternatifi alır .

  3. Uzantısız .phpkomut dosyaları için SetType veya SetHandler

    .phpURL'lerde sonekleri taşımaktan kaçınmak için daha yönlendirilmiş bir yaklaşım PHP işleyicisini diğer dosya şemaları için yapılandırmaktır . En basit seçenek, varsayılan MIME / işleyici türünü şu yöntemle geçersiz kılmaktır .htaccess:

    DefaultType application/x-httpd-php
    

    Bu şekilde article.phpbetiğinizi sadece article(uzantısız) olarak yeniden adlandırabilirsiniz , ancak yine de PHP betiği olarak işlenmesini sağlayabilirsiniz.

    Artık bunun bazı güvenlik ve performans etkileri olabilir, çünkü tüm uzantısız dosyalar şimdi PHP aracılığıyla iletilecektir. Bu nedenle, bu davranışı yalnızca tek tek dosyalar için de ayarlayabilirsiniz:

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

    Bu biraz sunucu kurulumunuza ve kullanılan PHP SAPI'ye bağlıdır. Ortak alternatifler ForceType application/x-httpd-phpveya AddHandler php5-script.

    Yine bu tür ayarların bir .htaccessklasörden alt klasörlere yayıldığını unutmayın . Statik kaynaklar ve yükleme / dizinler vb. İçin komut dosyası yürütmeyi ( SetHandler Noneve / Options -Execveya php_flag engine offvb.) Her zaman devre dışı bırakmalısınız .

  4. Diğer Apache yeniden yazma şemaları

    Birçok seçenek arasında Apache, mod_aliasbazen mod_rewriteRewriteRules kadar iyi çalışan özellikler de sunar . Ancak bunların çoğunun <VirtualHost>dizin başına .htaccessyapılandırma dosyalarında değil, bir bölümde ayarlanması gerektiğini unutmayın .

    • ScriptAliasMatchöncelikle CGI betikleri içindir, ancak PHP için de çalışmalıdır. Her şekilde olduğu gibi normal ifadelere izin verir RewriteRule. Aslında, tümünü yakalama ön denetleyicisini yapılandırmak belki de en sağlam seçenektir.

    • Ve bir sade Alias, birkaç basit yeniden yazma düzenine de yardımcı olur.

    • ErrorDocumentBir PHP komut dosyasının sanal yolları işlemesine izin vermek için düz bir yönerge bile kullanılabilir. Ancak bunun geçici bir çözüm olduğunu, GET istekleri dışında herhangi bir şeyi yasakladığını ve error.log dosyasını tanımına göre sular altında bıraktığını unutmayın.

    Daha fazla ipucu için http://httpd.apache.org/docs/2.2/urlmapping.html adresine bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.