Правило переписання Nginx замінити знак запитання на знак підкреслення


16

Щоб відобразити весь веб-сайт як статичний HTML,

Я хотів би перетворити URL - адреса , як http://example.com/script.php?t=12в http://example.com/script.php_t=12.

Повідомлення про ?URL перетворюється в _.

Це дозволить nginx або apache обслуговувати ці файли з диска як вихідний HTML, який ми отримали і зберегли з wget- по одному файлу для кожної URL-адреси, а не як PHP-файл.

Чи можливо це зробити за допомогою переписування URL-адреси Nginx?


Це, звичайно, можливо, але насправді дивно. Чого ти цього хочеш?
Олексій Десять

2
Одна з проблем цього підходу полягає в тому, що декілька параметрів GET в URL-адресі можуть бути в будь-якому порядку, і коли ви виконаєте це перетворення, ви зміните семантику URL-адреси.
Теро Кілканен

його для архівації старого форуму в статичному html, але так, щоб мати цю роботу, http://example.com/script.php?a=1&t=3знадобиться кілька надзвичайно вигадливих дій для перезапису
Сем Сафрон

1
@tero URL-адреси запитів на практиці завжди в одному порядку. Тож це не питання.
Джефф Етвуд

1
@chx - це для архівації старого форуму, тому аргумент може бути іншим, tяк f, наприклад u, тощо.
Арпіт Джалан

Відповіді:


15

У мене це працює за допомогою try_files:

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

Це спробує знайти файл на диску, названому за шаблоном, який ви надали "_" замість "?".

Подальша конфігурація залежить від того, як ви зберегли статичні файли, такі як зображення або таблиці стилів. Ви можете додати резервну копію, намагаючись прочитати їх без запиту рядка форми на зразок:

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

1
Дуже цікавий підхід, чи не спричинить це потенційний зчитування диска та "файл не знайдено" у всіх потенційних URL-адресах?
Джефф Етвуд

З try_files : "Перевіряє наявність файлів у вказаному порядку та використовує перший знайдений файл для обробки запиту". Таким чином, це не спричинить додаткових читання дисків для URL-адрес у вашому запитанні.
Маттіас Байєр

1
добре, якщо ми покладемо його, location ~ \.php$ми можемо приступити try_filesдо роботи, але це не працюєlocation /
Джефф Етвуд

+1 для прикладу використання фігурних брекетів :)
Данила Вершинін

4

Щось уздовж:

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

Ти не залишив використану ?мою відповідь.
chx

Ви маєте рацію? Що стосується вашої відповіді - мені знадобилося певний час, щоб перевірити його на реальному сервері, тому я не бачив ваших, поки я не розмістив свою. І ваш перепише всі URL-адреси навіть без аргументів на варіант "_", що може бути небажаним.
Макс Гашков

Рішення від Matthias з try_files насправді є більш кращим для цього.
Макс Гашков

ми можемо це зробити без if, коли .*в першому параметрі перезапису вкажемо більш суворе застереження. Це дуже корисно!
Джефф Етвуд

@JeffAtwood Я не думаю, що це можливо - шаблони переписування nginx (як і місцеположення) повинні застосовуватися лише до частини URL-адреси перед рядком запиту.
Макс Гашков

1

Я не думаю, що ви не зможете це зробити з ванільним 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({})
        ';

    }
}

Випробували його локально і, здається, роблять те, що шукаєте. Якщо ви хочете, щоб інші параметри були розділені амперсандами, змініть блок 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на диску, він спершу спробує з ним, а потім, якщо його немає, він піде script.php_t=12. try_filesпотрібна нещодавно версія nginx.

А якщо цього недостатньо, ви можете зробити це всередині if:

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

Мені це подобається, але ми не можемо отримати try_files біта насправді роботи, в той час як переписування робить роботу. (добре, якщо ви додасте ?туди в кінці свого переписування, щоб параметри запитів до нього не були додані ..)
Джефф Етвуд

@JeffAtwood try_filesзупиниться на $uriтому, що є блок розташування, що відповідає цьому, або файл для нього (запит без отримання аргументів) - це так?
AD7six

@JeffAtwood ?не має видимого впливу на статичні файли, ви побачите лише додатковий запит у своїх журналах доступу; якщо вас це хвилює, обов'язково додайте знак питання
sanmai

0

вікі каже

Якщо ви вказали? наприкінці перезаписання Nginx видалить початкові $ аргументи (аргументи).

Тож rewrite ^ ${uri}_$args? last;слід працювати.


nginx не зможе перезапустити цей набір правил -rewrite ^ $uri_$args? last;
Джефф Етвуд

Виправлено. $ -Bleeds-over-the-змінних відчуває себе PHP, яку я знаю, що ви просто любите.
chx

навіть із переглянутою версією, nginx не може перезапуститись
Джефф Етвуд

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параметра.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.