กฎ Nginx เขียนใหม่เพื่อแทนที่เครื่องหมายคำถามการสอบถามด้วยเครื่องหมายขีดล่าง


16

เพื่อแสดงทั้งเว็บไซต์เป็น HTML คงที่

ผมอยากจะแปลง URL เช่นการhttp://example.com/script.php?t=12http://example.com/script.php_t=12

แจ้งให้ทราบล่วงหน้า?ใน URL _จะถูกจะถูกแปลงเป็น

สิ่งนี้จะช่วยให้ nginx หรือ apache ให้บริการไฟล์เหล่านี้จากดิสก์เป็น HTML ดิบที่เราได้รับและบันทึกจากwget- หนึ่งไฟล์สำหรับแต่ละ URL - แทนที่จะเป็นไฟล์ PHP

เป็นไปได้หรือไม่ที่จะทำผ่านการเขียน URL Nginx ใหม่?


เป็นไปได้แน่นอน แต่แปลกมาก คุณต้องการทำอะไร
Alexey Ten

2
ปัญหาอย่างหนึ่งของวิธีนี้คือพารามิเตอร์หลาย GET ใน URL สามารถอยู่ในลำดับใดก็ได้และเมื่อคุณทำการแปลงนี้คุณจะเปลี่ยนซีแมนทิกส์ของ URL
Tero Kilkanen

สำหรับฟอรั่มเก็บเก่าใน html คงที่ แต่ใช่มีงานนี้ด้วยhttp://example.com/script.php?a=1&t=3จะไปต้องกระทำบางอย่างซุปเปอร์แฟนซีเขียน
แซม Saffron

1
@tero URL ของการสอบถามในทางปฏิบัติมักจะอยู่ในลำดับเดียวกันเสมอ ดังนั้นนี่ไม่ใช่ปัญหา
Jeff Atwood

1
@chx มันสำหรับเก็บฟอรั่มเก่าดังนั้นอาร์กิวเมนต์สามารถอื่น ๆ กว่าtเช่นf, uฯลฯ
Arpit Jalan

คำตอบ:


15

ฉันได้รับการทำงานโดยใช้ try_files:

location / {
    try_files "${uri}_${args}" 404.html;
}

วิธีนี้จะพยายามค้นหาไฟล์บนดิสก์ที่ตั้งชื่อตามรูปแบบที่คุณระบุด้วย "_" แทนที่จะเป็น "?"

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

location / {
    try_files "${uri}_${args}" $uri 404.html;
}

1
วิธีการที่น่าสนใจนี้จะทำให้ดิสก์อ่านและ "ไม่พบไฟล์" ใน URL ที่เป็นไปได้ทั้งหมดใช่หรือไม่
Jeff Atwood

จากtry_files : "ตรวจสอบการมีอยู่ของไฟล์ตามลำดับที่ระบุและใช้ไฟล์ที่พบครั้งแรกสำหรับการประมวลผลคำขอ" ดังนั้นสิ่งนี้จะไม่ทำให้ดิสก์อ่านเพิ่มเติมสำหรับ URL ในคำถามของคุณ
Matthias Bayer

1
ตกลงถ้าเราใส่ไว้ในlocation ~ \.php$เราสามารถtry_filesไปทำงาน แต่มันไม่ทำงานlocation /
Jeff Atwood

+1 สำหรับตัวอย่างของการใช้เครื่องหมายปีกกา :)
Danila Vershinin

4

บางสิ่งบางอย่างตามสาย:

location ~ \.php$ {
  # only rewrite URL's with args
  if ($args != '') {
    rewrite .* "${uri}_${args}?" last;
  }
}

คุณออกจาก?คำตอบของฉันที่ใช้
chx

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

การแก้ปัญหาจาก Matthias ด้วย try_files เป็นที่นิยมมากกว่าในเรื่องนี้
Max Gashkov

เราสามารถทำได้โดยไม่ต้องถ้าเมื่อเราระบุ.*อนุประโยคที่เข้มงวดยิ่งขึ้นใน param แรกที่เขียนใหม่ สิ่งนี้มีประโยชน์มหาศาล!
Jeff Atwood

@JeffAtwood ฉันไม่คิดว่าเป็นไปได้ควรใช้รูปแบบการเขียน (และตำแหน่ง) ของ nginx กับส่วนหนึ่งของ URL ก่อนที่จะใช้สตริงข้อความค้นหาเท่านั้น
Max Gashkov

1

ฉันไม่คิดว่าคุณจะสามารถทำสิ่งนี้กับ vanilla nginx แต่ถ้าคุณยินดีที่จะติดตั้งโมดูล Lua สำหรับ nginx ( http://wiki.nginx.org/HttpLuaModule ) คุณสามารถทำได้

server {
    server_name so.dev;
    listen 80;

    location / {

        root /tmp;

        rewrite_by_lua '
            local uri = ngx.var.uri
            local params = ngx.req.get_uri_args(0)

            for key, value in pairs(params) do
                uri = string.format("%s_%s=%s", uri, key, value)
            end

            ngx.req.set_uri(uri)
            ngx.req.set_uri_args({})
        ';

    }
}

ทดสอบในพื้นที่และดูเหมือนจะทำสิ่งที่คุณกำลังมองหา หากคุณต้องการให้ params อื่นคั่นด้วยเครื่องหมายแอมเปอร์แซนด์ให้เปลี่ยนบล็อก rewrite_by_lua เป็น

local uri = ngx.var.uri
local param_string = ""
local params = ngx.req.get_uri_args(0)
local separator = ""

for key, value in pairs(params) do
    param_string = param_string .. separator .. key .. "=" .. value
    separator = "&"
end

ngx.req.set_uri(uri .. "_" .. param_string)
ngx.req.set_uri_args({})

1

สิ่งนี้ใช้ได้กับ nginx / 1.6.2

rewrite ^/.*\.php$ "${uri}_${args}";

แต่ส่วนตัวผมจะใช้try_filesวิธีการแก้ปัญหาที่มีทางเลือกให้กับ URI เดิมหากมีใด ๆ

try_files $uri "${uri}_${args}";

เช่นถ้าคุณมีบนดิสก์มันจะลองกับมันเป็นครั้งแรกและจากนั้นถ้ามีใครมันจะไปscript.php ต้องการ nginx รุ่นล่าสุดscript.php_t=12try_files

และหากยังไม่เพียงพอคุณสามารถทำเช่นนี้ได้ภายในif:

return 301 "${uri}_${args}";

ผมชอบแบบนี้ แต่เราไม่สามารถรับ try_files บิตจริงการทำงานในขณะที่เขียนไม่ทำงาน (ดีถ้าคุณเพิ่ม?ไปยังจุดสิ้นสุดของการเขียนของคุณมีเพื่อ params แบบสอบถามจะไม่เพิ่มไป .. )
เจฟฟ์แอด

@JeffAtwood try_filesกำลังจะหยุด$uriถ้ามีบล็อกที่ตั้งตรงกับที่หรือไฟล์สำหรับมัน (คำขอโดยไม่ต้องรับ args) - เป็นกรณีที่?
AD7six

@JeffAtwood ?ไม่มีผลกระทบต่อไฟล์สแตติกคุณจะเห็นข้อความค้นหาเพิ่มเติมในบันทึกการเข้าถึงของคุณเท่านั้น หากคุณเป็นห่วงให้เพิ่มเครื่องหมายคำถามไว้
sanmai

0

วิกิพีเดียกล่าวว่า

หากคุณระบุ? ในตอนท้ายของการเขียนใหม่แล้ว Nginx จะวาง $ args ดั้งเดิม (อาร์กิวเมนต์)

ดังนั้นrewrite ^ ${uri}_$args? last;ควรทำงาน


nginx ล้มเหลวในการเริ่มต้นใหม่ด้วยชุดกฎนั้น -rewrite ^ $uri_$args? last;
Jeff Atwood

แก้ไขแล้ว. $ -bleeds-over-the-variables รู้สึกเหมือน PHP ที่ฉันรู้ว่าคุณรัก
chx

แม้จะมีรุ่นที่แก้ไขแล้ว nginx ล้มเหลวในการรีสตาร์ท
Jeff Atwood

0

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

http://example.com/script.php?t=12 // works 
http://example.com/script.php?t=12&_utm=twitter // not work

ข้อเสนอแนะของฉันคือการปล่อยให้ URL ตามที่เป็นอยู่และกำหนดเส้นทางไปยังไฟล์ที่ถูกต้องด้วย php คุณสามารถเข้าถึงtพารามิเตอร์

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