Reguła przepisywania Nginx, aby zastąpić pytający znak zapytania podkreśleniem


16

Aby wykonać kopię lustrzaną całej witryny jako statycznego HTML,

Chciałbym przekonwertować URL podobny http://example.com/script.php?t=12do http://example.com/script.php_t=12.

Zawiadomienie ?w adresie URL jest konwertowane na _.

Dzięki temu nginx lub apache będą mogły obsługiwać te pliki z dysku jako nieprzetworzony kod HTML, który uzyskaliśmy i zapisaliśmy wget- jeden plik dla każdego adresu URL - zamiast jako plik PHP.

Czy można to zrobić przez przepisywanie adresów URL Nginx?


Z pewnością jest to możliwe, ale naprawdę dziwne. Po co ci to?
Alexey Ten

2
Jednym z problemów związanych z tym podejściem jest to, że wiele parametrów GET w adresie URL może być w dowolnej kolejności, a po wykonaniu tej konwersji zmienisz semantykę adresu URL.
Tero Kilkanen,

http://example.com/script.php?a=1&t=3służy do archiwizacji starego forum w statycznym formacie HTML, ale tak, ta praca będzie wymagała super fantazyjnej operacji przepisywania
Sam Saffron

1
@ po pytających adresach URL są w praktyce zawsze w tej samej kolejności. To nie jest problem.
Jeff Atwood,

1
@chx to do archiwizacji starego forum, więc argument może być inna niż tjak f, uitp
Arpit Jalan

Odpowiedzi:


15

Mam to działa przy użyciu try_files:

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

Spowoduje to próbę znalezienia pliku na dysku o nazwie zgodnej ze wzorem podanym jako „_” zamiast „?”.

Dalsza konfiguracja zależy od sposobu zapisywania plików statycznych, takich jak obrazy lub arkusze stylów. Możesz dodać rezerwową próbę odczytania ich bez dysku z ciągiem zapytania w następujący sposób:

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

1
bardzo interesujące podejście, czy spowodowałoby to odczytanie potencjalnego dysku i „nie znaleziono pliku” we wszystkich potencjalnych adresach URL?
Jeff Atwood

Z try_files : „Sprawdza istnienie plików w określonej kolejności i wykorzystuje pierwszy znaleziony plik do przetwarzania żądania”. Nie spowoduje to żadnych dodatkowych odczytów dysku dla adresów URL w pytaniu.
Matthias Bayer,

1
ok, jeśli go location ~ \.php$włożymy, możemy zabrać się try_filesdo pracy, ale to nie działalocation /
Jeff Atwood

+1 na przykład za pomocą nawiasów klamrowych :)
Danila Vershinin

4

Coś wzdłuż linii:

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

Pominąłeś ?moją zastosowaną odpowiedź.
chx

Masz rację w odniesieniu do?, Jeśli chodzi o twoją odpowiedź - zajęło mi trochę czasu przetestowanie jej na prawdziwym serwerze, więc nie widziałem twojego, dopóki nie opublikowałem mojego. Twój przepisze wszystkie adresy URL, nawet bez argumentów, aby zmienić wariant na „_”, co może być niepożądane.
Max Gashkov

Rozwiązanie Matthiasa z try_files jest w rzeczywistości bardziej preferowane.
Max Gashkov

możemy to zrobić bez if, kiedy określimy bardziej surową .*klauzulę w pierwszym paragrafie przepisywania. Jest to niezwykle pomocne!
Jeff Atwood

@JeffAtwood Nie sądzę, że to możliwe - wzorce przepisywania (jak również lokalizacji) nginx powinny mieć zastosowanie do części adresu URL tylko przed ciągiem zapytania.
Max Gashkov

1

Nie sądzę, abyś mógł to zrobić za pomocą waniliowego nginx, ale jeśli chcesz zainstalować moduł Lua dla nginx ( http://wiki.nginx.org/HttpLuaModule ), możesz to zrobić.

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

    }
}

Przetestowałem to lokalnie i wydaje się, że robi to, czego szukasz. Jeśli chcesz, aby inne parametry były oddzielone znakami ampersands, zmień blok rewrite_by_lua na

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

Działa to na nginx / 1.6.2.

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

Ale osobiście użyłbym try_filesrozwiązania z rezerwą na oryginalny identyfikator URI, jeśli taki istnieje .

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

Np. Jeśli masz script.phpna dysku, najpierw spróbuje, a jeśli go nie ma, wybierze script.php_t=12. try_filespotrzebuje najnowszej wersji nginx.

A jeśli to nie wystarczy, możesz to zrobić w if:

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

To mi się podoba, ale nie możemy uzyskać try_files bit faktycznie praca, natomiast przepisać robi pracę. (cóż, jeśli dodasz ?tam napis na końcu przepisywania, aby parametry zapytania nie zostały do ​​niego dodane ...)
Jeff Atwood

@JeffAtwood try_fileszatrzyma się, $urijeśli istnieje blok lokalizacji pasujący do tego lub plik dla niego (żądanie bez argumentów) - czy tak jest w przypadku?
AD7six,

@JeffAtwood ?nie ma widocznego wpływu na pliki statyczne, w dziennikach dostępu zobaczysz tylko dodatkowe zapytanie; jeśli ci na tym zależy, dodaj znak zapytania
sanmai

0

Wiki mówi

Jeśli podasz? pod koniec przepisywania Nginx usunie oryginalne $ args (argumenty).

Więc to rewrite ^ ${uri}_$args? last;powinno działać.


Nginx nie uruchamia się ponownie z tym zestawem reguł -rewrite ^ $uri_$args? last;
Jeff Atwood

Naprawiony. $ -Bleeds-over-the-variable wydaje się być PHP, które po prostu kochasz.
chx

nawet przy poprawionej wersji nginx nie uruchamia się ponownie
Jeff Atwood

0

Odpowiedzi sugerowane powyżej powinny zadziałać. Widzisz jednak, jak wrażliwy staje się twój adres URL. Ponieważ nginx próbuje najpierw sprawdzić, czy nazwa pliku istnieje na serwerze, każdy dodatkowy parametr go wyrzuci.

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

Moją sugestią jest pozostawienie adresu URL bez zmian i przekierowanie go do pliku za pomocą php. Masz dostęp do tparametru.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.