เปลี่ยนเส้นทางเปลี่ยน URL หรือเปลี่ยนเส้นทาง HTTP เป็น HTTPS ใน Apache - ทุกสิ่งที่คุณอยากรู้เกี่ยวกับกฎ Mod_Rewrite แต่กลัวที่จะถาม


264

นี่เป็นคำถามที่ยอมรับได้เกี่ยวกับ mod_rewrite ของ Apache

การเปลี่ยน URL คำขอหรือเปลี่ยนเส้นทางผู้ใช้ไปยัง URL อื่นที่ไม่ใช่ URL ที่พวกเขาร้องขอ แต่เดิมนั้นทำได้โดยใช้ mod_rewrite ซึ่งรวมถึงสิ่งต่าง ๆ เช่น:

  • การเปลี่ยน HTTP เป็น HTTPS (หรือวิธีอื่น ๆ )
  • การเปลี่ยนการร้องขอไปยังหน้าที่ไม่มีอยู่ในการแทนที่ใหม่อีกต่อไป
  • การปรับเปลี่ยนรูปแบบ URL (เช่น? id = 3433 เป็น / id / 3433)
  • นำเสนอหน้าเว็บที่แตกต่างจากเบราว์เซอร์โดยอ้างอิงจากสิ่งที่เป็นไปได้ภายใต้แสงจันทร์และดวงอาทิตย์
  • ทุกสิ่งที่คุณต้องการยุ่งกับ URL

ทุกสิ่งที่คุณอยากรู้เกี่ยวกับกฎ Mod_Rewrite แต่ไม่กล้าถาม!

ฉันจะเป็นผู้เชี่ยวชาญในการเขียนกฎ mod_rewrite ได้อย่างไร

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

ที่สำหรับทดสอบกฎของคุณ

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


9
แนวคิดเบื้องหลังคำถามนี้คือให้แนวทางที่ใกล้ชิดกับคำถาม mod_rewrite ที่ไม่มีที่สิ้นสุดที่ทำให้ผู้ใช้ปกติของเราคลั่งไคล้มากขึ้น นี้จะคล้ายกับสิ่งที่ได้กระทำกับ subnetting ที่serverfault.com/questions/49765/how-does-subnetting-work
Kyle Brandt

1
นอกจากนี้ฉันไม่ต้องการ upvotes มากเกินไปสำหรับคำถามนี้แต่พวกเขาควรไปที่คำตอบ ฉันไม่ต้องการที่จะ CW นี้เพราะผมต้องการให้แน่ใจว่าโปสเตอร์ที่ได้รับเครดิตเต็มสำหรับสิ่งที่ผมหวังเป็นคำตอบที่จะยุติ mod_rewrite คำถาม
Kyle Brandt

4
ขออภัยฉันตอบคำถามแล้ว ;-) ฉันคิดว่ามันต้องแสดงที่ (หรือใกล้) ด้านบนสุดของmod-rewriteการค้นหา / ตัวกรองแท็ก
Steven Monday

บางคนอื่น (tm) ควรจัดการกรณีใช้งานทั่วไป ฉันไม่รู้จักพวกเขาดีพอที่จะทำในสิ่งที่ยุติธรรม
sysadmin1138

บางทีคำถามนี้ควรเชื่อมโยงเข้ากับแท็ก mod-rewrite เพื่อทำให้เส้นทางสั้นลง
beldaz

คำตอบ:


224

ลำดับไวยากรณ์ mod_rewrite

mod_rewrite มีกฎการสั่งซื้อเฉพาะบางอย่างที่ส่งผลต่อการประมวลผล ก่อนที่จะทำสิ่งใดเสร็จสิ้นRewriteEngine Onจำเป็นต้องมีคำสั่งเนื่องจากจะเปิดการประมวลผล mod_rewrite สิ่งนี้ควรอยู่ก่อนคำสั่งการแก้ไขอื่น ๆ

RewriteCondก่อนหน้านี้RewriteRuleทำให้กฎหนึ่งข้อขึ้นอยู่กับเงื่อนไข RewriteRules ต่อไปนี้จะถูกประมวลผลราวกับว่าพวกเขาไม่ได้อยู่ภายใต้เงื่อนไข

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html

ในกรณีที่ง่าย ๆ นี้ถ้าผู้อ้างอิง HTTP มาจาก serverfault.com ให้เปลี่ยนเส้นทางคำขอบล็อกไปยังหน้าเซิร์ฟเวอร์พิเศษ (เราเป็นเพียงผู้นั้น) อย่างไรก็ตามหากบล็อกด้านบนมีบรรทัด RewriteRule พิเศษ:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html
RewriteRule $/blog/(.*)\.jpg         $/blog/$1.sf.jpg

ไฟล์. jpg ทั้งหมดจะไปที่หน้าเซิร์ฟเวอร์ผิดปกติไม่ใช่เฉพาะไฟล์ที่มีผู้อ้างอิงที่ระบุว่ามาจากที่นี่ นี่ไม่ชัดเจนว่าเจตนาของวิธีการเขียนกฎเหล่านี้ สามารถทำได้หลายกฎของ RewriteCond:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

แต่อาจจะทำได้ด้วยไวยากรณ์การแทนที่ที่ซับซ้อน

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

RewriteRule ที่ซับซ้อนมากขึ้นมีเงื่อนไขสำหรับการประมวลผล parenthetical ล่าสุด(html|jpg)บอกให้ RewriteRule ตรงกันสำหรับอย่างใดอย่างหนึ่งhtmlหรือjpgและเพื่อแสดงสตริงที่ตรงกันเป็น $ 2 ในสตริงที่เขียนใหม่ สิ่งนี้มีเหตุผลเหมือนกันกับบล็อกก่อนหน้านี้ที่มีคู่ RewriteCond / RewriteRule สองคู่มันแค่ทำสองบรรทัดแทนสี่บรรทัด

หลายสาย RewriteCond เป็น ANDed โดยนัยและสามารถ ORed อย่างชัดเจน ในการจัดการผู้อ้างอิงจากทั้ง ServerFault และ Super User (ชัดแจ้ง OR):

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)    [OR]
RewriteCond %{HTTP_REFERER}                ^https?://superuser\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

วิธีแสดงหน้าอ้างอิง ServerFault ด้วยเบราว์เซอร์ Chrome (โดยนัยและ)

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteCond %{HTTP_USER_AGENT}             ^Mozilla.*Chrome.*$
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

RewriteBaseยังมีคำสั่งที่เฉพาะเจาะจงตามที่ระบุว่าRewriteRuleคำสั่งต่อไปนี้จัดการกับการประมวลผลอย่างไร มันมีประโยชน์มากในไฟล์. htaccess หากใช้ควรเป็นคำสั่งแรกภายใต้ "RewriteEngine on" ในไฟล์. htaccess ใช้ตัวอย่างนี้:

RewriteEngine On
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

สิ่งนี้กำลังบอก mod_rewrite ว่า URL นี้ซึ่งกำลังจัดการอยู่นั้นมาถึงโดยhttp://example.com/blog/แทนที่จะเป็นเส้นทางไดเรกทอรีทางกายภาพ (/ home / $ Username / public_html / blog) และปฏิบัติตาม ด้วยเหตุนี้จึงRewriteRuleถือว่าการเริ่มสตริงเป็นหลัง "/ บล็อก" ใน URL นี่คือสิ่งเดียวกันที่เขียนสองวิธีที่ต่างกัน หนึ่งรายการกับ RewriteBase อีกรายการหนึ่งที่ไม่มี:

RewriteEngine On

##Example 1: No RewriteBase##
RewriteCond %{HTTP_REFERER}                                   ^https?://serverfault\.com(/|$)
RewriteRule /home/assdr/public_html/blog/(.*)\.(html|jpg)     $1.sf.$2

##Example 2: With RewriteBase##
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

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


RewriteRule จับคู่ไวยากรณ์

RewriteRule เองมีไวยากรณ์ที่ซับซ้อนสำหรับสตริงที่ตรงกัน ฉันจะครอบคลุมธง (สิ่งที่ต้องการ [PT]) ในส่วนอื่น เนื่องจาก Sysadmins เรียนรู้จากตัวอย่างบ่อยกว่าการอ่านman-pageฉันจะยกตัวอย่างและอธิบายสิ่งที่พวกเขาทำ

RewriteRule ^/blog/(.*)$    /newblog/$1

.*สร้างตรงกับอักขระตัวเดียว ( .) ศูนย์หรือมากกว่าครั้ง ( *) ล้อมรอบไว้ในวงเล็บบอกให้จัดเตรียมสตริงที่ถูกจับคู่เป็นตัวแปร $ 1

RewriteRule ^/blog/.*/(.*)$  /newblog/$1

ในกรณีนี้ตัวแรก * ไม่ได้อยู่ใน parens ดังนั้นจึงไม่ได้จัดไว้ให้กับสตริงที่เขียนใหม่ กฎนี้จะลบระดับไดเรกทอรีในบล็อกไซต์ใหม่ (/blog/2009/sample.html จะกลายเป็น /newblog/sample.html)

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$2

ในกรณีนี้นิพจน์วงเล็บแรกจะตั้งค่ากลุ่มการจับคู่ สิ่งนี้กลายเป็น $ 1 ซึ่งไม่จำเป็นและดังนั้นจึงไม่ได้ใช้ในสตริงที่เขียนใหม่

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$1/$2

ในกรณีนี้เราใช้ $ 1 ในสตริงที่เขียนใหม่

RewriteRule ^/blog/(20[0-9][0-9])/(.*)$   /newblog/$1/$2

กฎนี้ใช้ไวยากรณ์ที่วงเล็บพิเศษที่ระบุตัวอักษรช่วง [0-9] ตรงกับตัวเลข 0 ถึง 9 กฎเฉพาะนี้จะจัดการปีจาก 2000 ถึง 2099

RewriteRule ^/blog/(20[0-9]{2})/(.*)$  /newblog/$1/$2

สิ่งนี้ทำสิ่งเดียวกันกับกฎก่อนหน้า แต่ส่วน {2} บอกให้ตรงกับอักขระก่อนหน้า (นิพจน์วงเล็บเหลี่ยมในกรณีนี้) สองครั้ง

RewriteRule ^/blog/([0-9]{4})/([a-z]*)\.html   /newblog/$1/$2.shtml

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

RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html  /newblog/$1/$2.shtml

กับดักชื่อไฟล์ที่มีขีดกลาง อย่างไรก็ตามเนื่องจาก-เป็นอักขระพิเศษในนิพจน์วงเล็บเหลี่ยมจึงต้องเป็นอักขระตัวแรกในนิพจน์

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

รุ่นนี้ดักจับชื่อไฟล์ใด ๆ ด้วยตัวอักษรตัวเลขหรือ-ตัวอักษรในชื่อไฟล์ นี่คือวิธีที่คุณระบุชุดอักขระจำนวนมากในนิพจน์วงเล็บเหลี่ยม


ธง RewriteRule

แฟล็กบนกฎการเขียนซ้ำมีโฮสต์ของความหมายและ usecasesพิเศษ

RewriteRule ^/blog/([0-9]{4})/([-a-z]*).\html  /newblog/$1/$2.shtml  [L]

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

L = ล่าสุด หยุดการประมวลผล RewriteRules เมื่อสิ่งนี้ตรงกัน คำสั่งซื้อนับ!
C = เชน ทำการประมวลผล RewriteRule ต่อไป หากกฎนี้ไม่ตรงกันกฎต่อไปจะไม่ถูกเรียกใช้ เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง
E = ตั้งค่าตัวแปรสภาพแวดล้อม Apache มีตัวแปรสภาพแวดล้อมต่าง ๆ ที่อาจส่งผลต่อพฤติกรรมของเว็บเซิร์ฟเวอร์
F = ต้องห้าม ส่งคืนข้อผิดพลาด 403 ที่ต้องห้ามถ้ากฎนี้ตรงกัน
G = หายไป ส่งคืนข้อผิดพลาด 410-Gone หากกฎนี้ตรงกัน
H = ตัวจัดการ บังคับให้คำร้องขอถูกจัดการราวกับว่าเป็นชนิด MIME ที่ระบุ
N = ถัดไป บังคับให้กฎเริ่มต้นใหม่อีกครั้งและจับคู่อีกครั้ง ระวัง! ลูปสามารถส่งผลให้
NC = ไม่มีกรณี ช่วยให้jpgเพื่อให้ตรงกับทั้ง jpg และ JPG
NE = ไม่มีทางหนีรอด ป้องกันการเขียนอักขระพิเศษ (.? # & etc) ลงในโค้ดเลขฐานสิบหก
NS = ไม่มีข้อความย่อย หากคุณใช้เซิร์ฟเวอร์รวมถึงสิ่งนี้จะป้องกันไม่ให้ตรงกับไฟล์ที่รวม
P = พร็อกซี บังคับใช้กฎที่จะจัดการโดย mod_proxy ให้เนื้อหาจากเซิร์ฟเวอร์อื่น ๆ อย่างโปร่งใสเนื่องจากเว็บเซิร์ฟเวอร์ของคุณดึงข้อมูลและให้บริการอีกครั้ง นี่คือการตั้งค่าสถานะที่เป็นอันตรายตามที่เขียนไม่ดีจะเปลี่ยนเว็บเซิร์ฟเวอร์ของคุณเป็นพร็อกซีเปิดและนั่นคือไม่ดี
PT = ผ่าน คำนึงถึงคำสั่ง Alias ​​ในการจับคู่ RewriteRule
QSA = QSAppend เมื่อสตริงเดิมมีข้อความค้นหา ( http://example.com/thing?asp=foo) ผนวกสตริงเคียวรีดั้งเดิมต่อท้ายสตริงที่เขียนใหม่ ปกติมันจะถูกทิ้ง สำคัญสำหรับเนื้อหาแบบไดนามิก
R = เปลี่ยนเส้นทาง ระบุการเปลี่ยนเส้นทาง HTTP ไปยัง URL ที่ระบุ ยังสามารถระบุรหัสการเปลี่ยนเส้นทางที่แน่นอน [R = 303] คล้ายกันมากRedirectMatchซึ่งเร็วกว่าและควรใช้เมื่อเป็นไปได้
S = ข้าม ข้ามกฏนี้
T = ประเภท ระบุประเภท mime ของเนื้อหาที่ส่งคืน คล้ายกับAddTypeคำสั่งมาก

คุณรู้ว่าฉันพูดว่าอย่างไรที่RewriteCondใช้กับกฎหนึ่งเดียวเท่านั้น? ทีนี้คุณก็สามารถทำได้โดยการผูกมัด

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html     [C]
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

เนื่องจาก RewriteRule แรกมีแฟล็กเชนกฎการเขียนซ้ำที่สองจะดำเนินการเมื่อครั้งแรกที่ทำซึ่งก็คือเมื่อกฎ RewriteCond ก่อนหน้าถูกจับคู่ มีประโยชน์ถ้าการแสดงออกปกติของ Apache ทำให้สมองของคุณเจ็บปวด อย่างไรก็ตามวิธี all-in-one-line ที่ฉันชี้ไปในส่วนแรกนั้นเร็วกว่าจากมุมมองการปรับให้เหมาะสมที่สุด

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

สิ่งนี้สามารถทำให้ง่ายขึ้นผ่านธง:

RewriteRule ^/blog/([0-9]{4})/([-0-9a-z]*)\.html   /newblog/$1/$2.shtml   [NC]

นอกจากนี้ธงบางรายการยังใช้กับ RewriteCond โดยเฉพาะอย่างยิ่ง NoCase

RewriteCond %{HTTP_REFERER}        ^https?://serverfault\.com(/|$)     [NC]

จะตรงกับ "ServerFault.com"


9
ทำได้ดี. [filler]
EEAA

3
mod_rewriteไพรเมอร์ที่ดีมากและ regex +1
Steven วันจันทร์ที่

3
มันมีประโยชน์ในบางครั้งที่รู้ว่าRewriteCondมีการประมวลผลจริงหลังจากRewriteRuleจะถูกจับคู่ คุณอาจต้องการพูดว่า "เพิ่มเติมในภายหลัง" ใกล้กับด้านบนที่คุณพูดว่า "RewriteCond ก่อนหน้า RewriteRule ทำให้กฎหนึ่งนั้นอยู่ภายใต้เงื่อนไข" คุณอาจต้องการพูดถึงว่า regexes เป็นนิพจน์ทั่วไปที่เข้ากันได้กับ Perl นอกจากนี้คุณยังมีเครื่องหมายอัญประกาศรอบนอกใน "... RewriteRule พิจารณาว่าเป็นจุดเริ่มต้น ... "
Dennis Williamson

2
RewriteRule ^/blog/.*/(.*)$ /newblog/$1ไม่ตรงกับองค์ประกอบไดเรกทอรีแรก - rewriterules เป็นโลภโดยค่าเริ่มต้น /.*/(.*) จับคู่ทั้ง / 1 / (2) / และ / 1/2/3/4/5 / (6) / ดังนั้นคุณต้อง / [^ /] * / เพื่อให้ตรงกับเส้นทางแรกเท่านั้น ส่วนประกอบ
adaptr

1
@ sysadmin1138 ฉันคิดว่าคำตอบนี้ดี แต่มันจะดีกว่าถ้าคุณอธิบายเพิ่มเติมเกี่ยวกับธง E, N, NS, P, PT และ S ด้วยตัวอย่างเนื่องจากค่าสถานะเหล่านั้นไม่ชัดเจนว่ามันทำงานอย่างไร ฯลฯ
Pacerier

39

รูปแบบและโครงสร้างพื้นฐานของกฎ mod_rewrite คืออะไร

ฉันจะเลื่อนไปยังคำตอบที่ยอดเยี่ยมของ sysadmin1138 ในประเด็นเหล่านี้

ฉันต้องมีรูปแบบ / รสชาติของการแสดงออกปกติอะไรบ้าง?

นอกเหนือจากลำดับไวยากรณ์การจับคู่ไวยากรณ์ / นิพจน์ปกติและธง RewriteRule ที่ระบุโดย sysadmin1138 ฉันเชื่อว่ามีการกล่าวถึงว่า mod_rewrite จะเปิดเผยตัวแปรสภาพแวดล้อมของ Apache ตามส่วนหัวคำขอ HTTP และการกำหนดค่าของ Apache

ฉันอยากจะแนะนำmod_rewrite Debug Tutorial ของ AskApacheสำหรับรายการตัวแปรที่ครอบคลุมซึ่งอาจมีให้ mod_rewrite

ข้อผิดพลาด / ผิดพลาดที่พบบ่อยที่สุดคืออะไรเมื่อเขียนกฎการเขียนใหม่

ปัญหาส่วนใหญ่เกี่ยวกับต้นกำเนิดของ RewriteRule จากความเข้าใจผิดของไวยากรณ์ / ความล้มเหลวของ PCRE ที่จะหลีกเลี่ยงอักขระพิเศษอย่างเหมาะสมหรือขาดความเข้าใจในเนื้อหาของตัวแปรที่ใช้สำหรับการจับคู่

ปัญหาทั่วไปและการแก้ไขปัญหาที่แนะนำ:

  • 500 - ข้อผิดพลาดเซิร์ฟเวอร์ภายใน - ลบการควบคุมการขนส่งของ Windowsในไฟล์การกำหนดค่าหากมีให้แน่ใจว่า mod_rewrite เปิดใช้งาน (ตัดคำสั่งแบบIfModuleมีเงื่อนไขเพื่อหลีกเลี่ยงสถานการณ์นี้) ตรวจสอบไวยากรณ์คำสั่งออกความคิดเห็นจนกว่าจะมีการระบุปัญหา
  • Redirect loop - ใช้ประโยชน์จาก RewriteLog และ RewriteLogLevel แสดงความคิดเห็นคำสั่งจนกว่าจะมีการระบุปัญหา

วิธีที่ดีในการทดสอบและตรวจสอบกฎ mod_rewrite คืออะไร

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

<?php
  var_dump($_SERVER);
?>

... จากนั้นเขียนกฎของคุณ (โดยเฉพาะอย่างยิ่งสำหรับการทดสอบบนเซิร์ฟเวอร์การพัฒนา) และจดบันทึกการจับคู่หรือกิจกรรมที่ไม่สอดคล้องกันในไฟล์Apache ErrorLog ของคุณ

สำหรับกฎที่ซับซ้อนมากขึ้นให้ใช้RewriteLogคำสั่งของ mod_rewrite เพื่อบันทึกกิจกรรมลงไฟล์และตั้งค่าRewriteLogLevel 3

มี SEO หรือนัยของประสิทธิภาพของกฎ mod_rewrite ที่ฉันควรระวังหรือไม่?

AllowOverride allส่งผลกระทบต่อประสิทธิภาพการทำงานของเซิร์ฟเวอร์เนื่องจาก Apache จะต้องตรวจสอบ.htaccessไฟล์และแยกวิเคราะห์คำสั่งแต่ละคำขอ - ถ้าเป็นไปได้เก็บคำสั่งทั้งหมดในการกำหนดค่า VirtualHost สำหรับเว็บไซต์ของคุณหรือเปิดใช้งานการ.htaccessแทนที่สำหรับไดเรกทอรีที่ต้องการเท่านั้น

หลักเกณฑ์ผู้ดูแลเว็บของ Google ระบุไว้อย่างชัดเจน: "อย่าหลอกลวงผู้ใช้ของคุณหรือนำเสนอเนื้อหาที่แตกต่างให้กับเครื่องมือค้นหามากกว่าที่คุณแสดงต่อผู้ใช้ซึ่งโดยทั่วไปจะเรียกว่า 'การปิดบัง'" - หลีกเลี่ยงการสร้างคำสั่ง mod_rewrite

หุ่นยนต์เครื่องมือค้นหาชอบ 1: 1 เนื้อหา: การทำแผนที่ URI (นี้เป็นพื้นฐานสำหรับการจัดอันดับการเชื่อมโยงกับเนื้อหา) - ถ้าคุณกำลังใช้ mod_rewrite เพื่อสร้างการเปลี่ยนเส้นทางชั่วคราวหรือคุณจะให้บริการเนื้อหาเดียวกันภายใต้หลาย URI ให้พิจารณาระบุบัญญัติ URIภายใน เอกสาร HTML ของคุณ

มีสถานการณ์ทั่วไปที่ mod_rewrite อาจดูเหมือนเป็นเครื่องมือที่เหมาะสมสำหรับงาน แต่ไม่ใช่หรือไม่?

นี่เป็นหัวข้อขนาดใหญ่ (และอาจเป็นที่ถกเถียงกัน) ในหัวข้อด้านขวา - ดีกว่า (IMHO) เพื่อจัดการกับการใช้งานเป็นกรณี ๆ ไปและให้ผู้ถามพิจารณาว่าการแก้ปัญหาที่เสนอนั้นเหมาะสมกับความต้องการของพวกเขาหรือไม่

ตัวอย่างทั่วไปมีอะไรบ้าง

เคล็ดลับและเคล็ดลับ mod_rewrite ของ AskApacheครอบคลุมทุกกรณีการใช้งานทั่วไปที่ปรากฏขึ้นเป็นประจำอย่างไรก็ตามโซลูชัน "ถูกต้อง" สำหรับผู้ใช้ที่กำหนดอาจขึ้นอยู่กับความซับซ้อนของการกำหนดค่าของผู้ใช้และคำสั่งที่มีอยู่ (ซึ่งเป็นเหตุผลทั่วไป ความคิดที่ดีที่จะดูว่าคนอื่น ๆสั่งที่ผู้ใช้มีในสถานที่เมื่อใดก็ตามที่เป็นคำถาม mod_rewrite ขึ้นมา)


ขอบคุณสำหรับลิงก์ AskApache มันคือสิ่งที่ฉันกำลังมองหา!
sica07

ตัวตลก AskApache ได้รับการสนับสนุนอย่างเป็นทางการจาก ASF สิ่งที่เขาพูดส่วนใหญ่เป็นที่ถกเถียงกันหรือผิดธรรมดา
adaptr

@adaptr โปรดแบ่งปันแหล่งข้อมูลที่เหนือกว่าซึ่งคุณรู้ตัวดีอยู่แล้ว
danlefree

"สถานการณ์ทั่วไปที่ mod_rewrite อาจดูเหมือนเครื่องมือที่เหมาะสมสำหรับงาน แต่ไม่ใช่" - การเปลี่ยนเส้นทางอย่างง่ายโดยที่ mod_rewrite ไม่ได้ถูกใช้งาน ใช้ mod_alias RedirectหรือRedirectMatchแทน โปรดดูเอกสาร Apache: เมื่อไม่ควรใช้ mod_rewrite
MrWhite

21

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

ต่อไปนี้เป็นความคิดเห็นที่สำคัญที่นักพัฒนากฎการเขียนใหม่ต้องพิจารณา:

  • บางแง่มุมของการเขียนใหม่เป็นเรื่องธรรมดาที่จะตั้งค่าเซิร์ฟเวอร์โฮสต์เสมือนไดเรกทอรี htaccess ของการประมวลผลอย่างไร
  • การประมวลผลบางอย่างแตกต่างกันมากสำหรับการกำหนดค่ารูท (การกำหนดค่าเซิร์ฟเวอร์โฮสต์เสมือนและไดเรกทอรี) ซึ่งตรงข้ามกับการ.htaccessประมวลผลPerDir ( )
  • ที่เลวร้ายยิ่งกว่าเนื่องจากการประมวลผล PerDir เกือบจะสามารถเรียกใช้การวนรอบ REDIRECT แบบไม่เจาะจงได้ดังนั้นองค์ประกอบการกำหนดค่ารูตจะต้องเขียนให้ทราบว่าการประมวลผล PerDir นั้นสามารถกระตุ้นสิ่งนี้ได้

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

  • ผู้ที่มีการเข้าถึงรากไป Apache การตั้งค่า โดยทั่วไปผู้ดูแลระบบ / นักพัฒนาที่มีแอปพลิเคชั่นเซิร์ฟเวอร์ / VM โดยเฉพาะและข้อความที่นี่ค่อนข้างง่าย: หลีกเลี่ยงการใช้.htaccessไฟล์หากเป็นไปได้ ทำทุกอย่างในเซิร์ฟเวอร์หรือ vhost config การดีบักค่อนข้างง่ายเนื่องจากผู้พัฒนาสามารถตั้งค่าการดีบักและสามารถเข้าถึงไฟล์ rewrite.log

  • ผู้ใช้บริการที่ใช้ร่วมกันเป็นเจ้าภาพ (SHS)

    • ผู้ใช้ดังกล่าวต้องใช้.htaccess/ การประมวลผล Perdir เนื่องจากไม่มีทางเลือกอื่น
    • ที่แย่กว่านั้นระดับความสามารถของผู้ใช้ดังกล่าว (เท่าที่ใช้บันไดตรรกะ regexp ที่ได้รับการดัดแปลงจาก mod_rewrite) โดยทั่วไปแล้วจะน้อยกว่าผู้ดูแลที่มีประสบการณ์
    • Apache และผู้ให้บริการโฮสต์ไม่สนับสนุนการแก้ไขข้อบกพร่อง / วินิจฉัย ข้อมูลการวินิจฉัยเพียงอย่างเดียวคือการเปลี่ยนเส้นทางที่ประสบความสำเร็จการเปลี่ยนเส้นทางไปยัง URI ที่ไม่ถูกต้อง หรือรหัสสถานะ 404/500 ทำให้พวกเขาสับสนและหมดหนทาง
    • Apache อ่อนแออย่างมากที่อธิบายวิธีการเขียนใหม่สำหรับกรณีการใช้งานนี้ ตัวอย่างเช่นมันไม่ได้ให้คำอธิบายที่ชัดเจนว่า.htaccessไฟล์PerDir ใดถูกเลือกและทำไม มันไม่ได้อธิบายถึงความซับซ้อนของการขี่จักรยาน PerDir และวิธีหลีกเลี่ยงปัญหานี้

อาจมีชุมชนที่สาม: ผู้ดูแลระบบและสนับสนุนพนักงานในผู้ให้บริการ SHS ที่จบด้วยการเดินเท้าในค่ายทั้งสองแห่งและต้องทนทุกข์ทรมานจากผลข้างต้น

ฉันได้เขียนบทความบล็อกในลักษณะบทความ (เช่นเพิ่มเติมเกี่ยวกับการใช้กฎการเขียนซ้ำในไฟล์. htaccess ) ซึ่งครอบคลุมจุดที่มีรายละเอียดมากมายซึ่งฉันจะไม่ทำซ้ำที่นี่เพื่อให้บทความนี้สั้น ฉันมีบริการที่ใช้ร่วมกันของตัวเองรวมถึงสนับสนุนโครงการเฉพาะ & VM FLOSS ฉันเริ่มใช้ LAMP VM มาตรฐานเป็นเครื่องมือทดสอบสำหรับบัญชี SHS ของฉัน แต่ในที่สุดฉันก็พบว่าทำกระจก VM ที่เหมาะสมได้ดีกว่า (อธิบายไว้ที่นี่ )

อย่างไรก็ตามในแง่ของชุมชนผู้ดูแลระบบที่ควรสนับสนุน.htaccessผู้ใช้ฉันรู้สึกว่าเราจำเป็นต้องพัฒนาและนำเสนอ:

  • คำอธิบายที่สอดคล้องกันว่าระบบการเขียนใหม่ทำงานอย่างไรในการประมวลผล PerDir
  • ชุดของแนวทาง / แนวปฏิบัติที่ดีที่สุดเกี่ยวกับวิธีเขียน.htaccessกฎการเขียนซ้ำ
  • Web parser script ที่ใช้งานง่ายเรียงลำดับคล้ายกับตัวแยกวิเคราะห์ h3 W3C แต่ผู้ใช้สามารถป้อน URI ทดสอบหรือเวกเตอร์ทดสอบเดียวกันและได้รับบันทึกทันทีของตรรกะการเขียน /
  • คำแนะนำในการรับการวินิจฉัยในตัวจากกฎของคุณ (เช่น

    • ใช้การใช้[E=VAR:EXPR]ประโยชน์จากข้อเท็จจริงที่EXPRจะขยายการอ้างอิงกลับ ($ N หรือ% N) เพื่อให้พร้อมใช้งานในฐานะการวินิจฉัยของสคริปต์เป้าหมาย
    • หากคุณเรียงลำดับกฎการเขียนใหม่โดยใช้ [OR], [C], [SKIP] และ [L] เพื่อให้ชุดรูปแบบการเขียนใหม่ทั้งหมดทำงานโดยไม่จำเป็นต้องใช้การเปลี่ยนเส้นทางภายในคุณสามารถเพิ่มสิ่งต่อไปนี้เป็นกฎ 1 เพื่อหลีกเลี่ยง ความยุ่งยากในการวนซ้ำทั้งหมด:

      RewriteCond %{ENV:REDIRECT_STATUS} !=""
      RewriteRule .  -  [L]
      

เอกสารนี้มีเอกสารครบถ้วน ทำไมคุณถึงบอกว่าเอกสารไม่ได้อธิบายสิ่งนี้?
adaptr

2
สิ่งที่คุณต้องทำคือการสมัครสมาชิก.htaccessหัวข้อและคุณจะเห็น ผู้เริ่มต้นส่วนใหญ่สับสนอย่างสิ้นหวัง - ส่วนใหญ่มีประสบการณ์ครั้งแรกในการให้บริการ LAMP และ mod_rewrite บนบริการที่ใช้ร่วมกันดังนั้นจึงไม่มีสิทธิ์เข้าถึงรูทของระบบ / vhost configs และต้องใช้การประมวลผล dir ผ่าน.htaccessไฟล์ มีความแตกต่างที่สำคัญซึ่งผู้เริ่มต้นต้อง "ตกเลือด" ฉันจะถือว่าตัวเองเป็นผู้ใช้ที่มีพลังและยังคงค้นพบรายละเอียดปลีกย่อย ในขณะที่ฉันบอกว่าฉันต้องใช้การสแกนแบบ strace และ source-source เพื่อหาบางแง่มุมไม่จำเป็นต้องทำ :-(
TerryE

ฉันเห็นด้วยอย่างยิ่ง "เราจำเป็นต้องแบ่งชุมชนผู้ใช้ที่เขียนใหม่ออกเป็นสองหมวดหมู่และถือว่าเป็นชุมชนที่แยกจากกันโดยสิ้นเชิง" ผู้ใช้บางรายใช้โฮสติ้งที่ใช้ร่วมกันและจำเป็นต้องพึ่งพา.htaccessซึ่งมีความเปราะบางมากซับซ้อนและสับสนแม้สำหรับผู้เชี่ยวชาญ ฉันยังคงมีปัญหา
Ryan

15

ใช้ rewritemap

มีหลายสิ่งที่คุณสามารถทำได้ด้วยการเขียนแผนที่ใหม่ Rewritemaps ได้รับการประกาศโดยใช้คำสั่ง Rewritemap และสามารถนำมาใช้ทั้งในการประเมินผล RewritCond และใน Subsitutions RewriteRule

ไวยากรณ์ทั่วไปสำหรับ RewriteMap คือ:

RewriteMap MapName MapType:MapSource

ตัวอย่างเช่น:

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

จากนั้นคุณสามารถใช้ mapname เพื่อสร้างสิ่งนี้:

${examplemap:key}

แผนที่มีคู่ของคีย์ / ค่า หากพบคีย์จะมีการชดเชยค่า แผนที่แบบง่ายเป็นเพียงไฟล์ข้อความธรรมดา แต่คุณสามารถใช้แผนที่แฮชและแม้แต่คิวรี่ SQL รายละเอียดเพิ่มเติมอยู่ในเอกสาร:

http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewritemap

การไม่ใช้สตริง

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

ตัวอย่างเช่นฉันต้องการทดสอบสตริง "café" ในสตริงข้อความค้นหา อย่างไรก็ตามเบราว์เซอร์จะหลบหนีสิ่งนี้ก่อนที่จะส่งไปยังเซิร์ฟเวอร์ของฉันดังนั้นฉันจะต้องคิดออกว่า URL ที่หลบหนีคืออะไรสำหรับทุก ๆ สตริงที่ฉันต้องการจับคู่หรือฉันสามารถ unescape ได้ ...

RewriteMap unescape int:unescape

RewriteCond %{QUERY_STRING}  (location|place)=(.*)
RewriteCond ${unescape:%2}   café
RewriteRule ^/find/$         /find/1234? [L,R]

สังเกตว่าฉันใช้ RewriteCond เพียงตัวเดียวเพื่อจับอาร์กิวเมนต์อาร์กิวเมนต์ของพารามิเตอร์สตริงการสืบค้นแล้วใช้แผนที่ใน rewriteCond อันที่สองเพื่อ unescape สิ่งนี้จะถูกเปรียบเทียบ โปรดทราบด้วยว่าฉันต้องการให้เรา% 2 เป็นกุญแจสำคัญในการเขียนใหม่อีกครั้งเนื่องจาก% 1 จะมี "ตำแหน่ง" หรือ "สถานที่" อย่างใดอย่างหนึ่ง เมื่อคุณใช้วงเล็บในการจัดกลุ่มรูปแบบพวกเขาก็จะถูกจับเช่นกันคุณวางแผนที่จะใช้ผลการจับภาพหรือไม่ ...


ประโยคสุดท้ายไม่เป็นความจริง เอ็นmod_rewriteจิ้น regexp สนับสนุนกลุ่มที่ไม่(?:location|place)ถูกดักจับเช่นและนี่จะมีเพียงหนึ่งการจับในตัวอย่าง
TerryE

12

ข้อผิดพลาด / ผิดพลาดที่พบบ่อยที่สุดคืออะไรเมื่อเขียนกฎการเขียนใหม่

อันตรายง่ายจริงๆคือเมื่อคุณเขียน URL ที่เปลี่ยนแปลงเส้นทางที่เห็นได้ชัดเช่นจาก การ/base/1234/index.html /base/script.php?id=1234รูปภาพหรือ CSS ใด ๆ ที่มีพา ธ สัมพัทธ์ไปยังตำแหน่งสคริปต์จะไม่ถูกพบโดยลูกค้า จำนวนของตัวเลือกในการแก้ไขปัญหานี้สามารถพบได้ในคำถามที่พบบ่อยนี้


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