การอ้างอิง: mod_rewrite, การเขียน URL ใหม่และอธิบาย "ลิงก์สวย"


142

"ลิงค์สวย" เป็นหัวข้อที่มักได้รับการร้องขอ แต่ไม่ค่อยได้รับการอธิบายอย่างสมบูรณ์ mod_rewriteเป็นวิธีหนึ่งในการทำ "ลิงค์สวย" แต่มันซับซ้อนและไวยากรณ์ของมันสั้นมากยากที่จะ grok และเอกสารประกอบถือว่าระดับความชำนาญใน HTTP ในระดับหนึ่ง บางคนสามารถอธิบายด้วยคำง่ายๆว่า "ลิงก์สวย ๆ " ทำงานอย่างไรและ mod_rewrite สามารถนำมาใช้สร้างได้อย่างไร

ชื่อสามัญอื่น ๆ , นามแฝง, เงื่อนไขสำหรับ URL ที่สะอาด: URL ที่สงบ , URL ที่ใช้งานง่าย, SEO - URL ที่เป็นมิตร, การบีบและ URL MVC (อาจเป็นชื่อที่ใช้ผิด)


2
Slug หรือ Slugging เป็นอีกชื่อ / คำทั่วไปสำหรับ URL ที่ค่อนข้างสวย
Mike B

2
@Mike Sort of แต่ตัวบุ้งมักเป็นส่วนหนึ่งของ URL ที่น่ารัก ตัวอย่างกระสุนสวยโดยเฉพาะเมื่อตัวอย่างเช่นพาดหัวของบทความจะเปลี่ยนเป็นรูปแบบที่เป็นมิตรกับ URL ซึ่งจะทำหน้าที่เป็นตัวระบุของบทความนั้น ดังนั้นreference-mod-rewrite-url-rewriting-explainedกระสุน/questions/20563772/reference-mod-rewrite-url-rewriting-explainedคือ URL ที่น่ารัก
หลอกลวง

2
ฉันคิดว่าควรติดตั้ง.htaccessและmod-rewriteแท็กเพื่อรวมลิงก์ไปยังคำถามนี้เนื่องจากครอบคลุมสิ่งที่ถูกถามเป็นประจำ คิด?
Mike Rockétt

คำตอบ:


110

เพื่อให้เข้าใจว่า mod_rewrite คุณต้องเข้าใจว่าเว็บเซิร์ฟเวอร์ทำงานอย่างไร ตอบสนองเว็บเซิร์ฟเวอร์เพื่อร้องขอ HTTP คำขอ HTTP ที่ระดับพื้นฐานที่สุดจะมีลักษณะดังนี้:

GET /foo/bar.html HTTP/1.1

นี่เป็นคำของ่ายๆของเบราว์เซอร์ไปยังเว็บเซิร์ฟเวอร์ที่ขอURL /foo/bar.htmlจากมัน เป็นสิ่งสำคัญที่จะต้องเน้นว่ามันไม่ได้ร้องขอไฟล์มันจะขอแค่ URL ที่กำหนดเอง คำขออาจมีลักษณะเช่นนี้:

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

นี่เป็นเพียงการร้องขอ URL ที่ถูกต้องและมีความชัดเจนมากขึ้นเกี่ยวกับไฟล์

เว็บเซิร์ฟเวอร์เป็นแอปพลิเคชั่นที่รับฟังพอร์ตยอมรับคำขอ HTTP ที่เข้ามาในพอร์ตนั้นและส่งคืนการตอบกลับ เว็บเซิร์ฟเวอร์นั้นมีอิสระที่จะตอบสนองต่อการร้องขอใด ๆ ในลักษณะที่เห็นว่าเหมาะสม / ไม่ว่าคุณจะกำหนดค่าให้ตอบสนองอย่างไร การตอบสนองนี้ไม่ใช่ไฟล์เป็นการตอบสนอง HTTPซึ่งอาจมีหรือไม่มีอะไรเกี่ยวข้องกับไฟล์ฟิสิคัลบนดิสก์ใด ๆ เว็บเซิร์ฟเวอร์ไม่จำเป็นต้องเป็น Apache มีเว็บเซิร์ฟเวอร์อื่น ๆ อีกมากมายซึ่งทั้งหมดเป็นเพียงโปรแกรมที่ทำงานอย่างต่อเนื่องและเชื่อมต่อกับพอร์ตที่ตอบสนองต่อคำขอ HTTP คุณสามารถเขียนเอง ย่อหน้านี้มีวัตถุประสงค์เพื่อหย่าคุณจากความคิดใด ๆ ที่ URL เท่ากับไฟล์โดยตรงซึ่งเป็นเรื่องสำคัญที่จะต้องเข้าใจ :)

การกำหนดค่าเริ่มต้นของเว็บเซิร์ฟเวอร์ส่วนใหญ่คือการค้นหาไฟล์ที่ตรงกับ URL บนฮาร์ดดิสก์ หากตั้งค่ารูทเอกสารของเซิร์ฟเวอร์เป็นพูด/var/wwwอาจดูว่ามีไฟล์/var/www/foo/bar.htmlอยู่หรือไม่และให้บริการหากเป็นเช่นนั้น หากไฟล์ลงท้ายด้วย ".php" ไฟล์จะเรียกล่าม PHP จากนั้นส่งคืนผลลัพธ์ การเชื่อมโยงทั้งหมดนี้สามารถกำหนดค่าได้อย่างสมบูรณ์ ไฟล์ไม่จำเป็นต้องลงท้ายด้วย ".php" เพื่อให้เว็บเซิร์ฟเวอร์เรียกใช้ผ่านตัวแปล PHP และ URL ไม่จำเป็นต้องจับคู่ไฟล์ใด ๆ บนดิสก์เพื่อให้มีบางอย่างเกิดขึ้น

mod_rewrite เป็นวิธีการเขียนการจัดการคำขอภายในใหม่ เมื่อเว็บเซิร์ฟเวอร์ได้รับคำขอ URL /foo/barคุณสามารถเขียน URL นั้นใหม่เป็นอย่างอื่นก่อนที่เว็บเซิร์ฟเวอร์จะค้นหาไฟล์บนดิสก์เพื่อจับคู่ ตัวอย่างง่ายๆ:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

กฎนี้บอกว่าเมื่อใดก็ตามที่คำขอตรงกับ "/ foo / bar" ให้เขียนใหม่เป็น "/ foo / baz" คำขอจะได้รับการจัดการราวกับว่า/foo/bazได้รับการร้องขอแทน สามารถใช้กับเอฟเฟ็กต์ต่างๆเช่น:

RewriteRule (.*) $1.html

กฎนี้ตรงกับสิ่งใด ( .*) และจับมัน ( (..)) จากนั้นเขียนใหม่เพื่อผนวก ".html" กล่าวอีกนัยหนึ่งถ้า/foo/barเป็น URL ที่ร้องขอมันจะถูกจัดการราวกับว่า/foo/bar.htmlได้รับการร้องขอ ดูhttp://regular-expressions.infoสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการจับคู่นิพจน์ปกติการจับภาพและการแทนที่

กฎอื่นที่พบบ่อยคือ:

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

สิ่งนี้จะจับคู่สิ่งใด ๆ และเขียนลงในไฟล์ index.php อีกครั้งด้วย URL ที่ร้องขอ แต่เดิมผนวกเข้ากับurlพารามิเตอร์การสืบค้น นั่นคือสำหรับคำขอใด ๆ และทั้งหมดที่เข้ามาไฟล์ index.php จะถูกดำเนินการและไฟล์นี้จะสามารถเข้าถึงคำขอต้นฉบับ$_GET['url']ได้ดังนั้นจึงสามารถทำสิ่งที่ต้องการได้

หลัก ๆ แล้วคุณวางกฎการเขียนซ้ำเหล่านี้ลงในไฟล์กำหนดค่าเว็บเซิร์ฟเวอร์ของคุณ Apache ยังอนุญาตให้คุณใส่ลงในไฟล์ที่เรียกว่า.htaccessภายในรูทเอกสารของคุณ (เช่นถัดจากไฟล์. php)

* หากได้รับอนุญาตจากไฟล์กำหนดค่า Apache หลัก มันเป็นตัวเลือก แต่เปิดใช้งานบ่อย

สิ่งที่ mod_rewrite ไม่ทำ

mod_rewrite ไม่ได้ทำให้ URL ของคุณ "สวย" ทั้งหมดอย่างน่าอัศจรรย์ นี่เป็นความเข้าใจผิดที่พบบ่อย หากคุณมีลิงค์นี้ในเว็บไซต์ของคุณ:

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

ไม่มีสิ่งใดที่ mod_rewrite สามารถทำได้เพื่อทำให้มันสวย ในการทำให้ลิงก์นี้เป็นลิงก์ที่สวยงามคุณต้อง:

  1. เปลี่ยนลิงค์เป็นลิงค์สวย:

    <a href="https://stackoverflow.com/my/pretty/link">
    
  2. ใช้ mod_rewrite บนเซิร์ฟเวอร์เพื่อจัดการการร้องขอไปยัง URL /my/pretty/linkโดยใช้วิธีใดวิธีหนึ่งที่อธิบายไว้ข้างต้น

(สามารถใช้mod_substituteร่วมกันเพื่อแปลงหน้า HTML ขาออกและลิงก์ที่มีอยู่แม้ว่านี่จะเป็นความพยายามมากกว่าการอัพเดททรัพยากร HTML ของคุณ)

มี mod_rewrite จำนวนมากที่สามารถทำได้และกฎการจับคู่ที่ซับซ้อนมากที่คุณสามารถสร้างรวมถึงการผูกหลาย rewrites คำขอ proxying ไปยังบริการที่แตกต่างกันโดยสิ้นเชิงหรือเครื่องกลับรหัสสถานะ HTTP เฉพาะเป็นการตอบสนองคำขอเปลี่ยนเส้นทาง ฯลฯ มันมีประสิทธิภาพมากและสามารถใช้ ดีมากถ้าคุณเข้าใจกลไกการตอบสนองคำร้องขอ HTTP พื้นฐาน มันไม่ได้ทำให้ลิงก์ของคุณสวยโดยอัตโนมัติ

ดูเอกสารอย่างเป็นทางการสำหรับธงและตัวเลือกที่เป็นไปได้ทั้งหมด


6
อาจพูดถึงคำสั่ง FallbackResource ที่นำมาใช้ในเวอร์ชั่น 2.2.16 เป็นวิธีการเขียนใหม่ไปยังโปรแกรมเลือกจ่ายงานล่วงหน้า
Darsstar

78

เพื่อขยายคำตอบของผู้หลอกลวงฉันต้องการยกตัวอย่างและคำอธิบายเกี่ยวกับฟังก์ชั่น mod_rewrite อื่น ๆ

ตัวอย่างด้านล่างทั้งหมดถือว่าคุณได้รวมไว้RewriteEngine Onใน.htaccessไฟล์แล้ว

เขียนซ้ำตัวอย่าง

ให้นำตัวอย่างนี้:

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

กฎแบ่งออกเป็น 4 ส่วน:

  1. RewriteRule - เริ่มกฎการเขียนซ้ำ
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - สิ่งนี้เรียกว่าลวดลาย แต่ฉันจะเรียกมันว่าเป็นด้านซ้ายมือของกฎ - สิ่งที่คุณต้องการเขียนใหม่จาก
  3. blog/index.php?id=$1&title=$2 - เรียกว่าการทดแทนหรือด้านขวามือของกฎการเขียนใหม่ - สิ่งที่คุณต้องการเขียนซ้ำ
  4. [NC,L,QSA] เป็นธงสำหรับกฎการเขียนซ้ำคั่นด้วยเครื่องหมายจุลภาคซึ่งฉันจะอธิบายเพิ่มเติมในภายหลัง

าการเขียนข้างต้นจะช่วยให้คุณสามารถเชื่อมโยงไปยังสิ่งที่ต้องการและเป็นจริงจะโหลด/blog/1/foo//blog/index.php?id=1&title=foo

ด้านซ้ายมือของกฎ

  • ^ระบุการเริ่มต้นของชื่อหน้า - ดังนั้นมันจะเขียนใหม่example.com/blog/...แต่ไม่ใช่example.com/foo/blog/...
  • (…)วงเล็บแต่ละชุดแสดงถึงนิพจน์ทั่วไปที่เราสามารถจับภาพเป็นตัวแปรทางด้านขวามือของกฎ ในตัวอย่างนี้:
    • วงเล็บชุดแรก - ([0-9]+)- จับคู่สตริงที่มีความยาวอย่างน้อย 1 อักขระและมีเฉพาะค่าตัวเลข (เช่น 0-9) สามารถอ้างอิงได้$1ที่ด้านขวามือของกฎ
    • วงเล็บชุดที่สองจับคู่สตริงที่มีความยาวอย่างน้อย 1 ตัวอักษรประกอบด้วยตัวอักษรและตัวเลข (AZ, az หรือ 0-9) เท่านั้น-หรือ+(หมายเหตุ+จะถูก Escape ด้วยเครื่องหมายแบ็กสแลชโดยไม่ต้องใช้ Escape มันจะดำเนินการเป็นregex ตัวอักษรซ้ำซ้อน ) สามารถอ้างอิงได้$2ที่ด้านขวามือของกฎ
  • ?หมายความว่าอักขระก่อนหน้านั้นเป็นทางเลือกดังนั้นในกรณีนี้ทั้งคู่/blog/1/foo/และ/blog/1/fooจะเขียนลงในที่เดียวกัน
  • $ ระบุว่านี่คือจุดสิ้นสุดของสตริงที่เราต้องการจับคู่

ธง

ตัวเลือกเหล่านี้เป็นตัวเลือกที่ถูกเพิ่มในวงเล็บเหลี่ยมที่ท้ายกฎการเขียนซ้ำของคุณเพื่อระบุเงื่อนไขบางอย่าง อีกครั้งมีการตั้งค่าสถานะแตกต่างกันมากมายซึ่งคุณสามารถอ่านได้ในเอกสารประกอบแต่ฉันจะผ่านการตั้งค่าสถานะทั่วไปเพิ่มเติมบางส่วน:

NC

แฟล็ก case หมายถึงว่ากฎการเขียนซ้ำไม่คำนึงถึงขนาดตัวพิมพ์ดังนั้นสำหรับตัวอย่างกฎด้านบนนี่หมายความว่าทั้งคู่/blog/1/foo/และ/BLOG/1/foo/(หรือการเปลี่ยนแปลงใด ๆ ของสิ่งนี้) จะถูกจับคู่

L

ธงล่าสุดบ่งชี้ว่านี่เป็นกฎล่าสุดที่ควรดำเนินการ ซึ่งหมายความว่าถ้าหากกฎนี้ตรงกันจะไม่มีการประเมินกฎเพิ่มเติมในการประมวลผลการเขียนซ้ำปัจจุบัน หากกฎไม่ตรงกันกฎอื่น ๆ ทั้งหมดจะถูกลองตามปกติ หากคุณไม่ได้ตั้งค่าLสถานะกฎต่อไปนี้ทั้งหมดจะถูกนำไปใช้กับURL ที่เขียนใหม่หลังจากนั้น

END

ตั้งแต่ Apache 2.4 คุณสามารถใช้การ[END]ตั้งค่าสถานะ กฎการจับคู่กับมันจะยุติการประมวลผลนามแฝง / เขียนใหม่อย่างสมบูรณ์ต่อไป (ในขณะที่การ[L]ตั้งค่าสถานะอาจเกิดรอบที่สองเช่นเมื่อเขียนใหม่หรือออกจากไดเรกทอรีย่อย)

QSA

สตริงการสืบค้นต่อท้ายสตริงช่วยให้เราสามารถส่งผ่านตัวแปรพิเศษไปยัง URL ที่ระบุซึ่งจะถูกเพิ่มเข้าไปในพารามิเตอร์รับต้นฉบับ สำหรับตัวอย่างของเรานี่หมายความว่าสิ่งที่ต้องการ/blog/1/foo/?comments=15จะโหลด/blog/index.php?id=1&title=foo&comments=15

R

ธงนี้ไม่ใช่ธงที่ฉันใช้ในตัวอย่างด้านบน แต่เป็นธงที่ฉันคิดว่าควรพูดถึง สิ่งนี้ช่วยให้คุณระบุการเปลี่ยนเส้นทาง http พร้อมตัวเลือกในการใส่รหัสสถานะ (เช่นR=301) ตัวอย่างเช่นหากคุณต้องการเปลี่ยนเส้นทาง 301 บน / myblog / to / blog / คุณเพียงแค่เขียนกฎดังนี้:

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

เงื่อนไขการเขียนซ้ำ

เงื่อนไขการเขียนซ้ำทำให้การเขียนมีประสิทธิภาพยิ่งขึ้นทำให้คุณสามารถระบุการเขียนซ้ำสำหรับสถานการณ์ที่เฉพาะเจาะจงมากขึ้น มีเงื่อนไขมากมายที่คุณสามารถอ่านได้ในเอกสารแต่ฉันจะสัมผัสตัวอย่างทั่วไปสองสามข้อและอธิบาย:

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

นี่เป็นวิธีปฏิบัติทั่วไปที่จะเพิ่มโดเมนของคุณด้วยwww.(หากยังไม่มี) และดำเนินการเปลี่ยนเส้นทาง 301 ตัวอย่างเช่นการโหลดhttp://example.com/blog/มันจะนำคุณไปยังhttp://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]

นี่เป็นเรื่องธรรมดาน้อยกว่าเล็กน้อย แต่เป็นตัวอย่างที่ดีของกฎที่ไม่ดำเนินการหากชื่อไฟล์เป็นไดเรกทอรีหรือไฟล์ที่มีอยู่บนเซิร์ฟเวอร์

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] จะดำเนินการเขียนซ้ำสำหรับไฟล์ที่มีนามสกุลไฟล์เป็น jpg, jpeg, gif หรือ png (ไม่คำนึงถึงขนาดตัวพิมพ์)
  • %{REQUEST_FILENAME} !-f จะตรวจสอบว่าไฟล์นั้นมีอยู่ในเซิร์ฟเวอร์ปัจจุบันหรือไม่และดำเนินการเขียนใหม่หากไม่เป็นเช่นนั้น
  • %{REQUEST_FILENAME} !-d จะตรวจสอบว่าไฟล์นั้นมีอยู่ในเซิร์ฟเวอร์ปัจจุบันหรือไม่และดำเนินการเขียนใหม่หากไม่เป็นเช่นนั้น
  • การเขียนซ้ำจะพยายามโหลดไฟล์เดียวกันในโดเมนอื่น

39

อ้างอิง

กองมากเกินมีหลายแหล่งข้อมูลที่ดีอื่น ๆ ที่จะเริ่มต้น:

และภาพรวม regex ที่เป็นมิตรกับผู้มาใหม่แม้:

ตัวยึดที่ใช้บ่อย

  • .*จับคู่อะไรก็ได้แม้เป็นสตริงว่าง คุณไม่ต้องการใช้รูปแบบนี้ทุกที่ แต่บ่อยครั้งในกฎทางเลือกสุดท้าย
  • [^/]+มักใช้สำหรับส่วนของเส้นทาง มันตรงกับอะไรก็ได้นอกจากเฉือนไปข้างหน้า
  • \d+ จับคู่สตริงตัวเลขเท่านั้น
  • \w+ตรงกับตัวอักษรและตัวเลข [A-Za-z0-9_]เป็นพื้นชวเลข
  • [\w\-]+สำหรับ "slug" - ส่วนของเส้นทางสไตล์ใช้ตัวอักษรตัวเลขเส้นประ- และ _
  • [\w\-.,]+เพิ่มจุดและเครื่องหมายจุลภาค ชอบ\-เส้นประที่หลบหนีใน[…]charclasses
  • \.หมายถึงช่วงเวลาที่แท้จริง มิฉะนั้น.ข้างนอก[…]เป็นตัวยึดสำหรับสัญลักษณ์ใด ๆ

ตัวยึดตำแหน่งเหล่านี้แต่ละตัวมักจะถูกห่อใน(…)วงเล็บเป็นกลุ่มจับภาพ และรูปแบบทั้งหมดมักจะอยู่ใน^………$เครื่องหมายเริ่มต้นและสิ้นสุด การอ้างถึง "รูปแบบ" เป็นตัวเลือก

RewriteRules

ตัวอย่างต่อไปนี้คือ PHP-centric และเพิ่มขึ้นอีกเล็กน้อยง่ายขึ้นที่จะปรับให้เข้ากับกรณีที่คล้ายกัน พวกเขาเป็นเพียงบทสรุปมักจะเชื่อมโยงกับรูปแบบอื่น ๆ หรือถาม & ตอบโดยละเอียด

  • การทำแผนที่แบบคงที่
    /contact,/about

    การย่อชื่อเพจให้สั้นลงในโครงร่างไฟล์ภายในนั้นง่ายที่สุด:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • ตัวระบุตัวเลข
    /object/123

    การแนะนำทางลัดเช่นhttp://example.com/article/531สคริปต์ PHP ที่มีอยู่ก็ทำได้ง่ายเช่นกัน ตัวยึดตำแหน่งที่เป็นตัวเลขสามารถแมปใหม่กับ$_GETพารามิเตอร์ได้:

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
     #                      └───────────────────────────┘
    
  • ตัวยึดสไตล์ทาก
    /article/with-some-title-slug

    คุณสามารถขยายกฎนั้นเพื่ออนุญาตสำหรับตัวแทนได้อย่างง่ายดาย/article/title-string:

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

    โปรดทราบว่าสคริปต์ของคุณ จะต้องสามารถ (หรือดัดแปลง) เพื่อแมปชื่อเหล่านั้นกลับไปที่รหัสฐานข้อมูล RewriteRules เพียงอย่างเดียวไม่สามารถสร้างหรือเดาข้อมูลจากอากาศที่บาง

  • ทากที่มีคำนำหน้าเป็นตัวเลข
    /readable/123-plus-title

    ดังนั้นคุณมักจะเห็น/article/529-title-slugเส้นทางผสมที่ใช้ในการฝึก:

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

    ตอนนี้คุณสามารถข้ามผ่านtitle=$2ไปได้เนื่องจากสคริปต์ของคุณมักจะใช้ฐานข้อมูล -ID -title-slugตกแต่ง URL ที่ได้กลายเป็นพล

  • ความสม่ำเสมอด้วยรายการทางเลือก
    /foo/… /bar/… /baz/…

    หากคุณมีกฎที่คล้ายกันสำหรับเส้นทางหน้าเสมือนหลาย ๆ เส้นทางคุณสามารถจับคู่และกระชับกับ|รายการทางเลือกอื่น และอีกครั้งเพียงกำหนดใหม่ให้กับพารามิเตอร์ GET ภายใน:

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

    คุณสามารถแยกพวกมันออกเป็นส่วนบุคคลRewriteRuleได้ถ้ามันซับซ้อนเกินไป

  • ส่ง URL ที่เกี่ยวข้องไปยังแบ็กเอนด์ที่แตกต่างกัน
    /date/SWITCH/backend

    การใช้รายการทางเลือกที่เป็นประโยชน์มากขึ้นคือการแมปเส้นทางคำขอไปยังสคริปต์ที่แตกต่าง ตัวอย่างเช่นเพื่อให้ URL ที่เหมือนกันสำหรับเว็บแอปพลิเคชันรุ่นเก่าและใหม่กว่าโดยอิงตามวันที่:

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

    สิ่งนี้ทำการแมป 2009-2011 ใหม่ไปยังสคริปต์หนึ่งรายการและอีกหลายปีที่ผ่านมาโดยอ้อมกับตัวจัดการอื่น หมายเหตุกฎเฉพาะเจาะจงมากขึ้นมาเป็นครั้งแรก แต่ละสคริปต์อาจใช้พารามิเตอร์ GET ที่แตกต่างกัน

  • ตัวคั่นอื่นที่ไม่ใช่แค่/เครื่องหมายสแลช
    /user-123-name

    คุณมักจะเห็น RewriteRules เพื่อจำลองโครงสร้างไดเรกทอรีเสมือน แต่คุณไม่ได้ถูกบังคับให้ไม่สร้างสรรค์ คุณสามารถใช้-ยัติภังค์สำหรับการแบ่งกลุ่มหรือโครงสร้าง

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

    สำหรับ/wiki:section:Page_Nameโครงการทั่วไปยัง:

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

    บางครั้งก็เหมาะสมที่จะสลับระหว่าง/-delimiters และ:หรือ.ในกฎเดียวกันแม้ หรือมีสอง RewriteRules อีกครั้งเพื่อแมปชุดตัวเลือกลงในสคริปต์ที่แตกต่างกัน

  • /ทับท้ายเผื่อเลือก
    /dir=/dir/

    เมื่อเลือกเส้นทางสไตล์ไดเรกทอรีคุณสามารถทำให้เข้าถึงได้โดยใช้และไม่มีจุดสิ้นสุด /

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

    ตอนนี้จับนี้ทั้งสองและhttp://example.com/blog/123 /blog/123/และ/?$วิธีการนั้นง่ายต่อการผนวกเข้ากับ RewriteRule อื่น ๆ

  • ส่วนที่ยืดหยุ่นสำหรับเส้นทางเสมือน
    .*/.*/.*/.*

    กฎส่วนใหญ่คุณจะพบแผนที่ชุด/…/กลุ่มเส้นทางทรัพยากรที่จำกัดกับพารามิเตอร์ GET แต่ละรายการ สคริปต์บางตัวจัดการกับตัวเลือกจำนวนตัวแปรอย่างไรก็ตาม เครื่องมือ Apache regexp ไม่อนุญาตให้เลือกหมายเลขที่ต้องการได้ แต่คุณสามารถขยายเป็นบล็อกกฎได้อย่างง่ายดาย:

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

    หากคุณต้องการส่วนของเส้นทางสูงสุดห้าส่วนให้คัดลอกชุดรูปแบบนี้พร้อมกับกฎห้าข้อ แน่นอนคุณสามารถใช้ตัวแทนที่เฉพาะเจาะจงมากขึ้น[^/]+ในแต่ละ การสั่งซื้อนี่ไม่สำคัญเท่ากับการเหลื่อมซ้อนกัน ดังนั้นการมีเส้นทางที่ใช้บ่อยที่สุดก่อนก็ไม่เป็นไร

    หรือคุณสามารถใช้พารามิเตอร์อาร์เรย์ PHPs ผ่าน?p[]=$1&p[]=$2&p[]=3สตริงการสืบค้นที่นี่ - หากสคริปต์ของคุณต้องการแบ่งล่วงหน้า (แม้ว่าจะเป็นเรื่องธรรมดามากกว่าที่จะใช้กฎ catch-all และปล่อยให้สคริปต์ขยายเซ็กเมนต์ออกจาก REQUEST_URI)

    ดูเพิ่มเติม: ฉันจะแปลงเซ็กเมนต์เส้นทาง URL ของฉันเป็นคู่ของคีย์ - ค่าสตริงข้อความค้นหาได้อย่างไร

  • ส่วนเสริม
    prefix/opt?/.*

    รูปแบบทั่วไปคือการมีคำนำหน้าเป็นตัวเลือกภายในกฎ โดยปกติแล้วจะเหมาะสมถ้าคุณมีสตริงคงที่หรือมีตัวยึดที่ จำกัด มากขึ้น:

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

    ตอนนี้รูปแบบที่ซับซ้อนมากขึ้น(?:/([^/])+)?มีเพียง wraps ไม่ใช่การจับภาพ กลุ่มและทำให้มันเป็นตัวเลือก(?:…) )?ตัวยึดที่มีอยู่([^/]+)จะเป็นรูปแบบการทดแทน$2แต่จะว่างเปล่าหากไม่มี/…/เส้นทางกลาง

  • จับส่วนที่เหลือ
    /prefix/123-capture/…/*/…whatever…

    ตามที่กล่าวไว้ก่อนหน้านี้คุณไม่ต้องการรูปแบบการเขียนซ้ำทั่วไปบ่อยเกินไป อย่างไรก็ตามการรวมการเปรียบเทียบแบบคงที่และแบบเฉพาะเข้ากับ.*บางครั้ง

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

    ส่วนนี้เป็นทางเลือกเสริม/…/…/…ส่วนเส้นทางใด ๆ ซึ่งก็แน่นอนต้องใช้สคริปต์การจัดการที่จะแยกพวกเขาขึ้นและปรับเปลี่ยนความ-Ifyพารามิเตอร์สกัดตัวเอง (ซึ่งเป็นสิ่งที่แม้แต่เชื่อมต่อ "MVC"กรอบทำ)

  • "ส่วนขยาย" ของไฟล์ต่อท้าย
    /old/path.HTML

    URL ไม่มีนามสกุลไฟล์จริง ๆ ซึ่งเป็นสิ่งที่การอ้างอิงทั้งหมดนี้เป็นเรื่องเกี่ยวกับ (= URL เป็นตัวระบุตำแหน่งเสมือนไม่จำเป็นต้องเป็นอิมเมจระบบไฟล์โดยตรง) อย่างไรก็ตามหากคุณเคยมีการแมปไฟล์ 1: 1 มาก่อนคุณสามารถสร้างกฎที่ง่ายขึ้นได้:

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

    การใช้งานทั่วไปอื่น ๆ คือการแมปพา ธ ที่ล้าสมัย.htmlไปยัง.phpตัวจัดการที่ใหม่กว่าหรือเพียงนามแฝงชื่อไดเรกทอรีเฉพาะสำหรับไฟล์ (จริง / จริง) แต่ละไฟล์

  • Ping-Pong (เปลี่ยนเส้นทางและเขียนใหม่พร้อมกัน)
    /ugly.html←→/pretty

    ดังนั้นในบางจุดที่คุณกำลังเขียนหน้าเว็บ HTML ของคุณเพื่อดำเนินการเพียงการเชื่อมโยงสวยเป็นที่ระบุไว้โดย deceze ในขณะเดียวกันคุณจะยังได้รับคำขอเส้นทางเก่าบางครั้งแม้แต่จากบุ๊คมาร์ค ในฐานะที่เป็นวิธีแก้ปัญหาที่คุณสามารถปิงปองเบราว์เซอร์ที่จะแสดงผล / สร้าง URL ใหม่

    เคล็ดลับทั่วไปนี้เกี่ยวข้องกับการส่งการเปลี่ยนเส้นทาง 30x / ตำแหน่งที่ตั้งเมื่อใดก็ตามที่ URL ขาเข้าเป็นไปตามรูปแบบการตั้งชื่อที่ล้าสมัย / น่าเกลียด เบราว์เซอร์จะทำการค้นหา URL ใหม่ / สวยซึ่งจะมีการเขียนใหม่ (ภายในเท่านั้น) ไปยังตำแหน่งเดิมหรือตำแหน่งใหม่

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

    สังเกตว่าตัวอย่างนี้ใช้เพียงแค่[END]แทนที่จะ[L]สลับอย่างปลอดภัย สำหรับ Apache 2.2 เวอร์ชันเก่ากว่าคุณสามารถใช้วิธีแก้ไขอื่น ๆ นอกจากนี้ยังทำการแมปพารามิเตอร์สตริงข้อความค้นหาใหม่อีกครั้ง: เปลี่ยนเส้นทางน่าเกลียดเป็น URL ที่น่ารักทำการแมปกลับไปที่เส้นทางน่าเกลียดโดยไม่มีลูปไม่สิ้นสุด

  • ช่องว่างในรูปแบบ
    /this+that+

    มันไม่ได้สวยขนาดนั้นในแถบที่อยู่ของเบราว์เซอร์ แต่คุณสามารถใช้ช่องว่างใน URL ได้ สำหรับรูปแบบการเขียนใหม่ให้ใช้\␣ช่องว่างที่มีเครื่องหมายทับกลับ อื่นเพียงแค่"ใช้รูปแบบหรือการทดแทนทั้งหมด:

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

    ไคลเอนต์เป็นอันดับ URL ด้วย+หรือ%20สำหรับช่องว่าง แต่ใน RewriteRules พวกมันจะถูกตีความด้วยตัวอักษรที่แท้จริงสำหรับส่วนของเส้นทางที่เกี่ยวข้องทั้งหมด

รายการซ้ำบ่อย:

.htaccessข้อผิดพลาดที่แพร่หลาย

ตอนนี้เอาเกลือเม็ดหนึ่งไปด้วย ไม่ใช่คำแนะนำทุกคำที่สามารถนำไปใช้กับบริบททั้งหมดได้ นี่เป็นเพียงบทสรุปง่ายๆของบล็อกที่รู้จักกันดีและสะดุดไม่กี่:

  • เปิดใช้งานmod_rewriteและ.htaccess

    ในการใช้ RewriteRules ในไฟล์กำหนดค่าต่อไดเรกทอรีคุณต้อง:

    • ตรวจสอบว่าเซิร์ฟเวอร์ของคุณได้เปิดใช้งานAllowOverride All มิฉะนั้น.htaccessคำสั่งต่อไดเรกทอรีของคุณจะถูกละเว้นและ RewriteRules จะไม่ทำงาน

    • เห็นได้mod_rewriteชัดว่ามีการเปิดใช้งานในhttpd.confส่วนโมดูลของคุณ

    • จัดทำรายการกฎแต่ละรายการด้วยRewriteEngine Onภาพนิ่ง ในขณะที่ mod_rewrite มีการใช้งานใน<VirtualHost>และ<Directory>ส่วนโดยปริยาย.htaccessไฟล์ต่อไดเรกทอรีจำเป็นต้องเรียกใช้แยกต่างหาก

  • เครื่องหมายทับ^/จะไม่ตรงกัน

    คุณไม่ควรเริ่ม.htaccessรูปแบบ RewriteRule ด้วย^/ตามปกติ:

     RewriteRule ^/article/\d+$  …
                  ↑
    

    สิ่งนี้มักจะเห็นในบทช่วยสอนเก่า ๆ และมันเคยถูกต้องสำหรับ Apache รุ่นโบราณ 1.x เส้นทางคำขอทุกวันนี้มีความสัมพันธ์อย่างเต็มที่กับไดเรกทอรีใน.htaccessRewriteRules เพียงแค่นำหน้า/ออกมา

    ·โปรดทราบว่าเครื่องหมายทับยังคงถูกต้องใน<VirtualHost>ส่วนที่ นี่คือเหตุผลที่คุณมักเห็นว่า^/?เป็นตัวเลือกสำหรับความเท่าเทียมกันของกฎ
    ·หรือเมื่อใช้งานRewriteCond %{REQUEST_URI}คุณจะยังคงเป็นผู้นำ/อยู่
    ·โปรดดูWebmaster.SE: เมื่อต้องการนำเครื่องหมายทับ (/) ในรูปแบบ mod_rewrite

  • <IfModule *> ห่อตัว!

    คุณอาจเห็นสิ่งนี้ในหลาย ๆ ตัวอย่าง:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • มันไม่ทำให้ความรู้สึกใน<VirtualHost>ส่วน - ถ้ามันได้ร่วมกับตัวเลือกทางเลือกอื่นเช่น ScriptAliasMatch (แต่ไม่มีใครทำอย่างนั้น)
    • และมันก็ถูกแจกจ่ายโดยทั่วไปสำหรับชุด.htaccessกฎเริ่มต้นที่มีโครงการโอเพ่นซอร์สมากมาย มันมีไว้เพื่อเป็นทางเลือกและทำให้ URL "น่าเกลียด" ทำงานเป็นค่าเริ่มต้น

    อย่างไรก็ตามคุณไม่ต้องการที่มักจะอยู่ใน.htaccessไฟล์ของคุณเอง

    • ประการแรก mod_rewrite ไม่ได้ปลดการสุ่ม (ถ้าเป็นเช่นนั้นคุณจะมีปัญหามากขึ้น)
    • หากใช้งานไม่ได้จริง ๆ RewriteRules ของคุณยังคงใช้งานไม่ได้
    • มันมีไว้เพื่อป้องกัน500ข้อผิดพลาดHTTP สิ่งที่มักจะประสบความสำเร็จคือการทำให้ผู้ใช้ของคุณมี404ข้อผิดพลาดHTTP แทน (ไม่เป็นมิตรกับผู้ใช้มากนักถ้าคุณคิดถึงมัน)
    • ในทางปฏิบัติมันจะหยุดรายการบันทึกที่มีประโยชน์มากขึ้นหรืออีเมลแจ้งเตือนของเซิร์ฟเวอร์ คุณจะไม่ฉลาดเท่านี้เพราะเหตุใด RewriteRules ของคุณจึงไม่ทำงาน

    สิ่งที่น่าดึงดูดในฐานะการป้องกันโดยทั่วไปมักจะกลายเป็นอุปสรรคในการปฏิบัติ

  • อย่าใช้RewriteBaseจนกว่าจำเป็น

    ตัวอย่างการคัดลอก + วางมีRewriteBase /คำสั่ง ซึ่งเกิดขึ้นเป็นค่าปริยายโดยปริยายเลยล่ะค่ะ ดังนั้นคุณไม่ต้องการสิ่งนี้จริงๆ มันเป็นวิธีการแก้ปัญหาสำหรับแผนการเขียนใหม่ VirtualHost แฟนซีและเส้นทาง DOCUMENT_ROOT ที่เข้าใจผิดสำหรับผู้ที่ได้รับการแบ่งปันบางคน

    มันสมเหตุสมผลที่จะใช้กับเว็บแอปพลิเคชันแต่ละตัวในไดเรกทอรีย่อยที่ลึกกว่า มันสามารถตัดทอนรูปแบบ RewriteRule ให้สั้นลงในกรณีเช่นนี้ โดยทั่วไปจะเป็นการดีกว่าหากต้องการเลือกตัวระบุพา ธ สัมพัทธ์ในชุดกฎต่อไดเรกทอรี

    ดูเพิ่มเติมRewriteBase ทำงานอย่างไรใน. htaccess

  • ปิดใช้งานMultiViewsเมื่อเส้นทางเสมือนทับซ้อนกัน

    การเขียน URL ใหม่ใช้เพื่อสนับสนุนเส้นทางขาเข้าเสมือนเป็นหลัก ปกติคุณเพียงแค่มีสคริปต์มอบหมายงานหนึ่ง ( index.php) หรือรถขนของแต่ละบุคคลไม่กี่ ( articles.php, blog.php, wiki.php, ... ) หลังอาจขัดแย้งกับเส้นทาง RewriteRule เสมือนที่คล้ายกัน

    คำขอ/article/123ตัวอย่างสามารถแมปarticle.phpกับ/123PATH_INFO โดยนัย คุณอาจจะต้องปกป้องกฎของคุณแล้วกับเรื่องธรรมดาRewriteCond !-f+ !-dและ / หรือการสนับสนุน PATH_INFO Options -MultiViewsปิดการใช้งานหรือบางทีอาจจะเป็นเพียงแค่ปิดการใช้งาน

    ซึ่งไม่ได้บอกว่าคุณต้องทำทุกครั้ง การเจรจาต่อรองเนื้อหาเป็นเพียงการทำให้ทรัพยากรเสมือนเป็นไปโดยอัตโนมัติ

  • การสั่งซื้อเป็นสิ่งสำคัญ

    ดูทุกสิ่งที่คุณอยากรู้เกี่ยวกับ mod_rewrite ถ้าคุณยังไม่มี การรวม RewriteRules หลายรายการเข้าด้วยกันมักจะนำไปสู่การโต้ตอบ นี่ไม่ใช่สิ่งที่จะป้องกันเป็นนิสัยต่อการ[L]ตั้งค่าสถานะ แต่เป็นรูปแบบที่คุณจะได้รับประสบการณ์ครั้งเดียว คุณสามารถเขียนเส้นทางเสมือนซ้ำอีกครั้งจากกฎหนึ่งไปอีกกฎหนึ่งจนกว่าจะถึงตัวจัดการเป้าหมายที่แท้จริง

    แต่คุณก็ยังต้องการมักจะต้องการที่จะมีกฎระเบียบมากที่สุดโดยเฉพาะ (สตริงคง/forum/…รูปแบบหรือตัวยึดที่ จำกัด มากขึ้น[^/.]+) ในช่วงต้นกฎ ทั่วไป Slurp ทุกกฎ ( .*) จะเหลือดีกว่าที่จะต่อมาคน (ข้อยกเว้นคือRewriteCond -f/-dการ์ดป้องกันเป็นบล็อกหลัก)

  • สไตล์และรูปภาพหยุดทำงาน

    เมื่อคุณแนะนำโครงสร้างไดเรกทอรีเสมือนสิ่ง/blog/article/123นี้จะส่งผลกระทบต่อการอ้างอิงทรัพยากรที่เกี่ยวข้องใน HTML (เช่น<img src=mouse.png>) ซึ่งสามารถแก้ไขได้โดย:

    • ใช้การอ้างอิงแบบสัมบูรณ์เซิร์ฟเวอร์เท่านั้นhref="https://stackoverflow.com/old.html"หรือsrc="/logo.png"
    • บ่อยครั้งโดยเพิ่ม<base href="https://stackoverflow.com/index">ลงใน<head>ส่วนHTML ของคุณ สิ่งนี้จะเชื่อมโยงการอ้างอิงที่สัมพันธ์กับสิ่งที่เคยเป็นก่อนหน้า

    คุณสามารถประดิษฐ์ RewriteRules เพิ่มเติมเพื่อเชื่อมใหม่.cssหรือ.pngเส้นทางไปยังตำแหน่งเดิม แต่นั่นเป็นสิ่งที่ไม่จำเป็นหรือมีการเปลี่ยนเส้นทางและการแคชเพิ่มขึ้นเป็นพิเศษ

    ดูเพิ่มเติมที่: CSS, JS และรูปภาพไม่แสดงพร้อม url ที่สวย

  • RewriteConds เพียงซ่อนหนึ่ง RewriteRule

    การผิดพลาดที่พบบ่อยคือ RewriteCond จะบล็อก RewriteRules หลาย ๆ อัน

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

    ซึ่งมันไม่ได้ตามค่าเริ่มต้น คุณสามารถโยงพวกเขาโดยใช้[S=2]ธง มิฉะนั้นคุณจะต้องทำซ้ำพวกเขา ในขณะที่บางครั้งคุณสามารถสร้างกฎหลัก "กลับด้าน" เป็น [END] การประมวลผลการเขียนใหม่ในช่วงต้น

  • QUERY_STRING ได้รับการยกเว้นจาก RewriteRules

    คุณไม่สามารถจับคู่ได้RewriteRule index.php\?x=yเนื่องจาก mod_rewrite เปรียบเทียบกับเส้นทางญาติต่อค่าเริ่มต้น คุณสามารถจับคู่แยกต่างหากผ่าน:

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

    ดูเพิ่มเติมฉันจะจับคู่ตัวแปรสตริงข้อความค้นหากับ mod_rewrite ได้อย่างไร

  • .htaccess เมื่อเทียบกับ <VirtualHost>

    หากคุณใช้ RewriteRules ในไฟล์กำหนดค่าต่อไดเรกทอรีการกังวลเกี่ยวกับประสิทธิภาพของ regex นั้นไม่มีจุดหมาย Apache รักษารูปแบบ PCRE ที่คอมไพล์แล้วยาวกว่ากระบวนการ PHP ด้วยเฟรมเวิร์กการกำหนดเส้นทางทั่วไป สำหรับเว็บไซต์ที่มีปริมาณการใช้งานสูงคุณควรพิจารณาย้ายชุดกฎไปยังการกำหนดค่าเซิร์ฟเวอร์ vhost เมื่อพวกเขาผ่านการทดสอบการต่อสู้แล้ว

    ในกรณีนี้ให้เลือก^/?คำนำหน้าตัวคั่นไดเรกทอรีที่เลือกกำหนดได้ ซึ่งช่วยให้สามารถย้าย RewriteRules ได้อย่างอิสระระหว่าง PerDir และไฟล์กำหนดค่าเซิร์ฟเวอร์

  • เมื่อใดก็ตามที่บางสิ่งไม่ทำงาน

    หงุดหงิดไม่ได้

    • เปรียบเทียบaccess.logและerror.log

      บ่อยครั้งที่คุณสามารถคิดออกว่า misbehaves RewriteRule เพียงจากการมองที่คุณและerror.log access.logสัมพันธ์เวลาในการเข้าถึงเพื่อดูว่ามีคำขอเส้นทางใดที่เริ่มต้นมาและ Apache / ไฟล์ใดที่ไม่สามารถแก้ไขได้ (ข้อผิดพลาด 404/500)

      สิ่งนี้ไม่ได้บอกคุณว่า RewriteRule เป็นตัวการ แต่เส้นทางสุดท้ายที่เข้าไม่ถึงอย่างเช่น/docroot/21-.itle?index.phpอาจให้ที่ที่จะตรวจสอบเพิ่มเติม มิฉะนั้นปิดใช้งานกฎจนกว่าคุณจะได้รับเส้นทางที่คาดเดาได้

    • เปิดใช้งาน RewriteLog

      ดูเอกสารApache RewriteLog สำหรับการดีบักคุณสามารถเปิดใช้งานได้ในส่วน vhost:

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

      นั่นเป็นบทสรุปโดยละเอียดเกี่ยวกับวิธีขอเส้นทางที่เข้ามาได้รับการแก้ไขโดยแต่ละกฎ

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

      ซึ่งช่วยในการ จำกัด กฎทั่วไปที่มากเกินไปและความผิดพลาดของ regex

      ดูเพิ่มเติมที่:
      ·. htaccess ไม่ทำงาน (mod_rewrite)
      · คำแนะนำสำหรับการดีบักกฎ. htaccess เขียนใหม่

    • ก่อนถามคำถามของคุณเอง

      อย่างที่คุณอาจทราบแล้ว Stack Overflow เหมาะมากสำหรับการถามคำถามเกี่ยวกับ mod_rewrite ทำให้พวกเขาในหัวข้อ โดยรวมถึงการวิจัยก่อนหน้านี้และความพยายาม (หลีกเลี่ยงคำตอบซ้ำซ้อน) แสดงให้เห็นถึงพื้นฐาน ความเข้าใจและ:

      • รวมตัวอย่างที่สมบูรณ์ของ URL อินพุตเส้นทางเป้าหมายที่เขียนใหม่อย่างไม่ถูกต้องโครงสร้างไดเรกทอรีจริงของคุณ
      • ชุด RewriteRule ที่สมบูรณ์ แต่ยังแยกชุดที่มีข้อบกพร่องออก
      • เวอร์ชัน Apache และ PHP, ประเภท OS, ระบบไฟล์, DOCUMENT_ROOT และ$_SERVERสภาพแวดล้อมPHPs ถ้ามันเกี่ยวกับพารามิเตอร์ที่ไม่ตรงกัน
      • ข้อความที่ตัดตอนมาจากคุณaccess.logและerror.logเพื่อตรวจสอบว่ากฎที่มีอยู่ได้รับการแก้ไขอย่างไร rewrite.logสรุปยังดีกว่า

      วิธีนี้จะช่วยให้คำตอบที่รวดเร็วและแม่นยำยิ่งขึ้นและทำให้ผู้อื่นมีประโยชน์มากขึ้น

  • แสดงความคิดเห็นของคุณ .htaccess

    # comment and origin linkหากคุณคัดลอกตัวอย่างจากที่ไหนสักแห่งที่ดูแลจะรวมถึง ในขณะที่มันเป็นแค่มารยาทที่ไม่ดีที่จะละเว้นการระบุแหล่งที่มา แต่ก็มักจะเจ็บการบำรุงรักษาในภายหลัง เอกสารรหัสใด ๆ หรือแหล่งที่มาของการสอน โดยเฉพาะอย่างยิ่งในขณะที่ไม่ถูกยกเลิกคุณควรให้ความสนใจมากขึ้นในการไม่รักษามันเช่นกล่องดำเวทมนตร์

  • ไม่ใช่ "SEO" -URLs

    คำเตือน: เพียงแค่สัตว์เลี้ยงโกรธ คุณมักจะได้ยินแผนการเขียน URL ใหม่ที่เรียกว่าลิงก์ "SEO" หรือบางสิ่งบางอย่าง แม้ว่าสิ่งนี้มีประโยชน์สำหรับตัวอย่างของ googling แต่เป็นชื่อเรียกผิดที่ลงวันที่

    ไม่มีเครื่องมือค้นหาสมัยใหม่ที่ถูกรบกวนโดย.htmlและ.phpในส่วนของเส้นทางหรือ?id=123สตริงการสืบค้นสำหรับเรื่องนั้น เสิร์ชเอนจิ้นรุ่นเก่าเช่น AltaVista ได้หลีกเลี่ยงการรวบรวมข้อมูลเว็บไซต์ที่มีเส้นทางการเข้าถึงที่น่าสงสัย ซอฟต์แวร์รวบรวมข้อมูลที่ทันสมัยมักจะอยากได้ทรัพยากรเว็บลึก

    อะไรคือ "สวย" URL ที่ควร conceptionally จะใช้สำหรับการคือการทำให้เว็บไซต์ที่ใช้งานง่าย

    1. มีโครงร่างทรัพยากรที่อ่านได้และชัดเจน
    2. การทำให้แน่ใจว่า URL มีอายุใช้งานยาวนาน ( permalink AKA )
    3. /common/tree/nestingให้ค้นพบผ่าน

    อย่างไรก็ตามอย่าเสียสละความต้องการที่เป็นเอกลักษณ์สำหรับความสอดคล้อง

เครื่องมือ

มีเครื่องมือออนไลน์มากมายในการสร้าง RewriteRules สำหรับ URL GET-parameterish ส่วนใหญ่:

ส่วนใหญ่เพียงแค่เอาท์พุท[^/]+ตัวยึดตำแหน่งทั่วไป แต่มีแนวโน้มเพียงพอสำหรับไซต์ที่ไม่สำคัญ


ยังคงต้องการการเขียนใหม่การเชื่อมโยงมากขึ้นและหัวเรื่องย่อยจำนวนมากค่อนข้างน่าสะพรึงกลัว มีบางคำซ้อนทับกับคำตอบอื่น ๆ ที่นี่ดังนั้นอาจถูกตัดทอน มันเกี่ยวกับตัวอย่างภาพเป็นหลักและรายการ gotchas ทั่วไปนั้น
มาริโอ

3
ไม่เห็นคำตอบที่สวยงามเช่นนี้มานานแล้ว! ดวงตาของฉันเปล่งประกายในขณะที่ฉันกำลังอ่าน โปรดอย่าหยุดโพสต์คำตอบดังกล่าว :)
Rizier123

1
โพสต์ที่ยอดเยี่ยม ทำให้ฉันเข้าใจแนวคิดพื้นฐานของ mod_rewrite เร็วมาก!
breez

6

ทางเลือกเพื่อ mod_rewrite

แบบแผน URL เสมือนพื้นฐานหลาย ๆ แบบสามารถทำได้โดยไม่ต้องใช้ RewriteRules Apache อนุญาตให้สคริปต์ PHP สามารถเรียกใช้โดยไม่มี.phpนามสกุลและมีPATH_INFOอาร์กิวเมนต์เสมือน

  1. ใช้PATH_INFO , ลุค

    ทุกวันนี้AcceptPathInfo Onมักเปิดใช้งานตามค่าเริ่มต้น ซึ่งโดยทั่วไปจะอนุญาต.phpและ URL ทรัพยากรอื่น ๆ เพื่อดำเนินการโต้แย้งเสมือน:

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

    ตอนนี้/virtual/pathจะปรากฏใน PHP เป็น$_SERVER["PATH_INFO"]ที่ที่คุณสามารถจัดการข้อโต้แย้งพิเศษใด ๆ ที่คุณต้องการ

    นี้ไม่ได้เป็นความสะดวกที่มี Apache ส่วนเส้นทางการป้อนข้อมูลที่แยกต่างหากเข้า$1, $2, $3และผ่านพวกเขาเป็นที่แตกต่างกัน$_GETตัวแปร PHP มันเป็นเพียงการเลียนแบบ "URL ที่สวยงาม" ด้วยความพยายามกำหนดค่าที่น้อย

  2. เปิดใช้งานMultiViewsเพื่อซ่อน.phpส่วนขยาย

    ตัวเลือกที่ง่ายที่สุดในการหลีกเลี่ยง.php"นามสกุลไฟล์" ใน URL ก็คือ:

    Options +MultiViews
    

    ตัวเลือกนี้มี Apache ให้เลือกarticle.phpสำหรับคำขอ HTTP /articleเนื่องจากมีชื่อฐานที่ตรงกัน และใช้งานได้ดีพร้อมกับคุณสมบัติ PATH_INFO ดังกล่าว ดังนั้นคุณก็สามารถใช้ URL http://example.com/article/virtual/titleเช่น ซึ่งเหมาะสมถ้าคุณมีเว็บแอปพลิเคชันแบบดั้งเดิมที่มีหลายจุด / สคริปต์การเรียกใช้ PHP

    โปรดทราบว่า MultiViews มีจุดประสงค์ที่แตกต่าง / กว้างกว่า มันเกิดโทษประสิทธิภาพเล็กน้อยเพราะ Apache มักจะมองหาไฟล์อื่น ๆ ที่มีพื้นฐานการจับคู่ มันหมายจริงสำหรับเนื้อหาการเจรจาต่อรองเพื่อให้เบราว์เซอร์ได้รับทางเลือกที่ดีที่สุดในหมู่ทรัพยากรที่มีอยู่ (เช่นarticle.en.php, article.fr.php, article.jp.mp4)

  3. SetType หรือ SetHandler สำหรับ.phpสคริปต์ที่ไม่มีส่วนขยาย

    แนวทางที่ชัดเจนยิ่งขึ้นเพื่อหลีกเลี่ยงการดำเนินการ.phpคำต่อท้ายใน URL คือการกำหนดค่าตัวจัดการ PHPสำหรับรูปแบบไฟล์อื่น ๆ ตัวเลือกที่ง่ายที่สุดคือการแทนที่ประเภท MIME / ตัวจัดการเริ่มต้นผ่าน.htaccess:

    DefaultType application/x-httpd-php
    

    วิธีนี้คุณสามารถเปลี่ยนชื่อarticle.phpสคริปต์ของคุณเป็นเพียงarticle(ไม่ต้องมีส่วนขยาย) แต่ยังคงมีการประมวลผลเป็นสคริปต์ PHP

    ตอนนี้สิ่งนี้อาจมีผลกระทบด้านความปลอดภัยและประสิทธิภาพเนื่องจากไฟล์ส่วนขยายทั้งหมดจะถูกไพพ์ผ่าน PHP ตอนนี้ ดังนั้นคุณสามารถตั้งค่าพฤติกรรมนี้สำหรับแต่ละไฟล์เท่านั้น:

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

    สิ่งนี้ขึ้นอยู่กับการตั้งค่าเซิร์ฟเวอร์ของคุณและ PHP SAPI ที่ใช้ ทางเลือกที่พบบ่อย ได้แก่หรือForceType application/x-httpd-phpAddHandler php5-script

    อีกครั้งโปรดทราบว่าการตั้งค่าดังกล่าวแพร่กระจายจากหนึ่ง.htaccessไปยังโฟลเดอร์ย่อย คุณควรปิดการใช้งานสคริปต์การดำเนินการ ( SetHandler NoneและOptions -Execหรือphp_flag engine offอื่น ๆ ) สำหรับทรัพยากรคงที่และอัพโหลด / ไดเรกทอรีเป็นต้น

  4. ชุดรูปแบบการเขียนใหม่ของ Apache อื่น ๆ

    Apache มีmod_aliasฟีเจอร์ให้เลือกมากมายซึ่งบางครั้งก็ใช้งานได้ดีกับmod_rewriteRewriteRules โปรดทราบว่าส่วนใหญ่จะต้องตั้งค่าใน<VirtualHost>ส่วนอย่างไรก็ตามไม่ได้อยู่ใน.htaccessไฟล์กำหนดค่าต่อไดเรกทอรี

    • ScriptAliasMatchมีไว้สำหรับสคริปต์ CGI เป็นหลัก แต่ก็ควรทำงานกับ PHP ด้วย จะช่วยให้ regexps RewriteRuleเช่นเดียวใด ๆ ในความเป็นจริงอาจเป็นตัวเลือกที่แข็งแกร่งที่สุดในการกำหนดค่าตัวควบคุมด้านหน้าแบบ catch-all

    • และแบบธรรมดาก็Aliasช่วยให้มีวิธีการเขียนใหม่ที่เรียบง่ายเช่นกัน

    • แม้แต่ErrorDocumentคำสั่งธรรมดาสามารถใช้เพื่อให้สคริปต์ PHP จัดการกับเส้นทางเสมือน โปรดทราบว่านี่เป็นวิธีแก้ปัญหา kludgy ห้ามมิให้มีสิ่งใดนอกจากคำขอ GET และทำให้ error.log ตามนิยาม

    ดูhttp://httpd.apache.org/docs/2.2/urlmapping.htmlสำหรับเคล็ดลับเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.