Правило перезаписи 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и т. д.
Arpit Jalan

Ответы:


15

Я получил это с помощью try_files:

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

Это попытается найти файл на диске, названный в соответствии с шаблоном, который вы указали с «_» вместо «?».

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

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

1
очень интересный подход, не вызовет ли это потенциальное чтение диска и «файл не найден» на всех потенциальных URL?
Джефф Этвуд

From 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, когда мы указываем более строгое .*предложение в первом параметре rewrite. Это очень полезно!
Джефф Этвуд

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

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

    }
}

Протестировано локально и, кажется, делает то, что вы ищете. Если вы хотите, чтобы другие параметры были разделены амперсандами, измените блок 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если есть блок местоположения, соответствующий этому, или файл для него (запрос без аргументов get) - так ли это?
AD7six

@JeffAtwood не ?оказывает видимого влияния на статические файлы, вы увидите только дополнительный запрос в журналах доступа; если вы заботитесь об этом, обязательно добавьте знак вопроса
sanmai

0

Вики говорит

Если вы укажете? в конце перезаписи Nginx удалит исходные $ args (аргументы).

Так что тогда rewrite ^ ${uri}_$args? last;должно работать.


nginx не может перезапуститься с этим набором правилrewrite ^ $uri_$args? last;
Джефф Этвуд

Исправлена. $ -Bleeds-over-the-variable ощущается как 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.