Aturan penulisan ulang nginx untuk mengganti tanda tanya querystring dengan garis bawah


16

Untuk mencerminkan seluruh situs web sebagai HTML statis,

Saya ingin mengonversi URL http://example.com/script.php?t=12ke http://example.com/script.php_t=12.

Pemberitahuan ?dalam URL sedang dikonversi ke _.

Ini akan memungkinkan nginx atau apache untuk menyajikan file-file ini dari disk sebagai HTML mentah yang kami peroleh dan simpan dari wget- satu file untuk setiap URL - bukan sebagai file PHP.

Apakah mungkin untuk melakukannya melalui penulisan ulang URL Nginx?


Itu memang mungkin, tetapi sangat aneh. Untuk apa Anda menginginkannya?
Alexey Ten

2
Satu masalah dengan pendekatan ini adalah bahwa beberapa parameter GET dalam URL dapat dalam urutan apa pun, dan ketika Anda melakukan konversi ini, Anda akan mengubah semantik URL.
Tero Kilkanen

itu untuk pengarsipan forum lama di html statis, tapi ya memiliki pekerjaan ini dengan http://example.com/script.php?a=1&t=3akan memerlukan beberapa tindakan menulis ulang super mewah
Sam Saffron

1
@tero URL querystring, dalam praktiknya, selalu dalam urutan yang sama. Jadi ini bukan masalah.
Jeff Atwood

1
@chx itu untuk pengarsipan sebuah forum lama, sehingga argumen dapat selain tseperti f, u, dll
Arpit Jalan

Jawaban:


15

Saya berhasil menggunakan try_files:

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

Ini akan mencoba menemukan file pada disk yang dinamai sesuai pola yang Anda berikan dengan "_" alih-alih "?".

Konfigurasi lebih lanjut tergantung pada bagaimana Anda menyimpan file statis seperti gambar atau stylesheet. Anda dapat menambahkan fallback mencoba membacanya tanpa disk bentuk string kueri seperti:

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

1
pendekatan yang sangat menarik, apakah ini akan menyebabkan disk potensial membaca dan "file tidak ditemukan" pada semua URL potensial?
Jeff Atwood

Dari try_files : "Memeriksa keberadaan file dalam urutan yang ditentukan dan menggunakan file yang ditemukan pertama kali untuk pemrosesan permintaan". Jadi ini tidak akan menyebabkan disk tambahan membaca URL dalam pertanyaan Anda.
Matthias Bayer

1
ok, jika kita memasukkannya ke dalam, location ~ \.php$kita bisa mulai try_filesbekerja, tetapi itu tidak berhasillocation /
Jeff Atwood

+1 sebagai contoh menggunakan kurung kurawal :)
Danila Vershinin

4

Sesuatu di sepanjang garis:

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

Anda mengabaikan ?jawaban saya yang digunakan.
chx

Anda benar sehubungan dengan ?, Adapun jawaban Anda — perlu beberapa waktu untuk mengujinya di server nyata, jadi saya belum melihat milik Anda sampai saya memposting milik saya. Dan Anda akan menulis ulang semua URL bahkan tanpa argumen untuk varian dengan "_" apa yang mungkin tidak diinginkan.
Max Gashkov

Solusi dari Matthias dengan try_files sebenarnya lebih disukai untuk ini.
Max Gashkov

kita bisa melakukannya tanpa if, ketika kita menentukan .*klausa yang lebih ketat di param menulis ulang pertama. Ini sangat membantu!
Jeff Atwood

@JeffAtwood Saya pikir itu tidak mungkin — pola nginx rewrite (dan juga lokasi) harus diterapkan pada bagian URL sebelum string kueri saja.
Max Gashkov

1

Saya tidak berpikir Anda akan dapat melakukan ini dengan vanilla nginx tetapi jika Anda bersedia menginstal modul Lua untuk nginx ( http://wiki.nginx.org/HttpLuaModule ) Anda dapat melakukannya.

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({})
        ';

    }
}

Mengujinya secara lokal dan tampaknya melakukan apa yang Anda cari. Jika Anda ingin agar params lain dipisahkan oleh ampersand, ubah blok rewrite_by_lua menjadi

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

Ini bekerja pada nginx / 1.6.2.

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

Tetapi secara pribadi saya akan menggunakan try_filessolusi dengan fallback ke URI asli jika ada .

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

Misalnya jika Anda memiliki script.phppada disk itu akan mencoba dulu, dan kemudian, jika tidak ada, itu akan berlaku script.php_t=12. try_filesmembutuhkan versi nginx yang cukup baru.

Dan jika ini tidak cukup, Anda bisa melakukan ini di dalam if:

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

Saya suka ini, tapi kami tidak bisa mendapatkan try_files sedikit untuk benar-benar bekerja, sedangkan menulis ulang melakukan pekerjaan. (well, jika Anda menambahkan a ?ke akhir penulisan ulang Anda di sana sehingga params kueri tidak ditambahkan ke sana ..)
Jeff Atwood

@JeffAtwood try_filesakan berhenti $urijika ada blok lokasi yang cocok dengan itu, atau file untuk itu (permintaan tanpa get args) - apakah itu masalahnya?
AD7six

@JeffAtwood ?tidak memiliki efek yang terlihat pada file statis, Anda hanya akan melihat permintaan tambahan di log akses Anda; jika Anda peduli tentang hal itu, pastikan tambahkan tanda tanya
sanmai

0

The wiki mengatakan

Jika Anda menentukan? pada akhir penulisan ulang maka Nginx akan menjatuhkan $ args asli (argumen).

Maka rewrite ^ ${uri}_$args? last;harus bekerja.


nginx gagal memulai kembali dengan aturan yang ditetapkan -rewrite ^ $uri_$args? last;
Jeff Atwood

Tetap. $ -Bleeds-over-the-variable terasa seperti PHP yang saya tahu Anda sukai.
chx

bahkan dengan versi revisi, nginx gagal untuk memulai ulang
Jeff Atwood

0

Jawaban yang disarankan di atas harus bekerja. Namun Anda melihat seberapa sensitifnya URL Anda. Karena nginx mencoba memeriksa apakah nama file ada di server terlebih dahulu, setiap parameter tambahan akan membuangnya.

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

Saran saya adalah meninggalkan URL apa adanya dan mengarahkannya ke file yang benar dengan php. Anda memiliki akses ke tparameter.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.