Nginx-Umschreiberegel, um das Querystring-Fragezeichen durch einen Unterstrich zu ersetzen

16

Um eine ganze Website als statisches HTML zu spiegeln,

Ich möchte URLs konvertieren , wie http://example.com/script.php?t=12zu http://example.com/script.php_t=12.

Hinweis ?in URL wird konvertiert _.

Auf diese Weise kann Nginx oder Apache diese Dateien von der Festplatte als unformatiertes HTML bereitstellen, das wir erhalten und gespeichert haben wget- eine Datei für jede URL - und nicht als PHP-Datei.

Ist dies über das Umschreiben von Nginx-URLs möglich?

Arpit Jalan
quelle
Es ist sicherlich möglich, aber wirklich komisch. Wofür willst du es?
Alexey Ten
2
Ein Problem bei diesem Ansatz besteht darin, dass mehrere GET-Parameter in einer URL in einer beliebigen Reihenfolge vorliegen können. Wenn Sie diese Konvertierung durchführen, ändern Sie die Semantik der URL.
Tero Kilkanen
Es ist für die Archivierung eines alten Forums in statischem HTML, aber ja, diese Arbeit mit http://example.com/script.php?a=1&t=3wird einige super
Sam Saffron
1
@tero Die Querystring-URLs sind in der Praxis immer in derselben Reihenfolge. Das ist also kein Problem.
Jeff Atwood
1
@chx es ist ein altes Forum für die Archivierung, so kann das Argument anders als twie f, uetc.
Arpit Jalan

Antworten:

15

Ich habe diese Arbeit mit try_files:

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

Dadurch wird versucht, eine Datei auf der Festplatte zu finden, die nach dem Muster benannt ist, das Sie mit einem "_" anstelle des "?"

Die weitere Konfiguration hängt davon ab, wie Sie statische Dateien wie Bilder oder Stylesheets gespeichert haben. Sie können einen Fallback hinzufügen, der versucht, sie ohne Abfragezeichenfolge auf dem Datenträger zu lesen:

location / {
    try_files "${uri}_${args}" $uri 404.html;
}
Matthias Bayer
quelle
1
Sehr interessanter Ansatz. Würde dies dazu führen, dass die Festplatte gelesen und die Datei nicht auf allen potenziellen URLs gefunden wird?
Jeff Atwood
Aus try_files : "Überprüft das Vorhandensein von Dateien in der angegebenen Reihenfolge und verwendet die zuerst gefundene Datei für die Anforderungsverarbeitung." Dies führt also nicht zu zusätzlichen Lesevorgängen für die URLs in Ihrer Frage.
Matthias Bayer,
1
ok, wenn wir es location ~ \.php$reinlegen, können wir try_filesarbeiten, aber es funktioniert nicht inlocation /
Jeff Atwood
+1 zum Beispiel mit geschweiften Klammern :)
Danila Vershinin
4

Etwas in die richtige Richtung:

location ~ \.php$ {
  # only rewrite URL's with args
  if ($args != '') {
    rewrite .* "${uri}_${args}?" last;
  }
}
Max Gashkov
quelle
Sie haben die von ?mir verwendete Antwort ausgelassen .
CHX
In Bezug auf? Haben Sie recht, was Ihre Antwort betrifft - ich habe einige Zeit gebraucht, um sie auf einem echten Server zu testen, also habe ich Ihre erst gesehen, als ich meine veröffentlicht habe. Und Ihr wird alle URLs auch ohne Argumente umschreiben, um mit "_" zu variieren, was möglicherweise unerwünscht ist.
Max Gashkov
Lösung von Matthias mit try_files ist dem eigentlich vorzuziehen.
Max Gashkov
Wir können dies ohne if tun, wenn wir .*im ersten Rewrite-Parameter eine strengere Klausel angeben. Das ist sehr hilfreich!
Jeff Atwood
@ JeffAtwood Ich denke nicht, dass das möglich ist - Nginx-Umschreibe-Muster (sowie Standort-Muster) sollten nur auf einen Teil einer URL vor der Abfrage angewendet werden.
Max Gashkov
1

Ich glaube nicht, dass Sie dies mit Vanille-Nginx tun können, aber wenn Sie bereit sind, das Lua-Modul für Nginx ( http://wiki.nginx.org/HttpLuaModule ) zu installieren , können Sie es tun.

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

    }
}

Getestet es vor Ort und scheint zu tun, was Sie suchen. Wenn Sie andere Parameter durch Et-Zeichen voneinander trennen möchten, ändern Sie den Block rewrite_by_lua in

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({})
c17r
quelle
1

Dies funktioniert unter Nginx / 1.6.2.

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

Persönlich würde ich jedoch eine try_filesLösung mit einem Fallback auf einen ursprünglichen URI verwenden, falls vorhanden .

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

Wenn Sie z. B. eine script.phpFestplatte haben, wird diese zuerst ausprobiert, und wenn keine vorhanden ist, wird sie verwendet script.php_t=12. try_filesbenötigt eine aktuelle Version von Nginx.

Und wenn dies nicht genug ist, können Sie dies in einem tun if:

return 301 "${uri}_${args}";
sanmai
quelle
Ich mag das, aber wir können nicht die try_files bekommen Bit tatsächlich Arbeit zu, während die Rewrite tut Arbeit. ( ?Nun , wenn Sie am Ende Ihres Umschreibens dort ein hinzufügen , damit die Abfrageparameter nicht hinzugefügt werden ..)
Jeff Atwood
@ JeffAtwood try_fileswird anhalten, $uriwenn es einen passenden Standortblock gibt, oder eine Datei dafür (die Anfrage ohne Argumente) - ist das der Fall?
AD7six
@JeffAtwood ?hat keine sichtbaren Auswirkungen auf statische Dateien. In Ihren Zugriffsprotokollen wird nur eine zusätzliche Abfrage angezeigt . Wenn es Ihnen etwas
ausmacht
0

Das Wiki sagt

Wenn Sie ein? Am Ende eines Umschreibens löscht Nginx die ursprünglichen $ args (Argumente).

Also rewrite ^ ${uri}_$args? last;sollte das funktionieren.

chx
quelle
nginx startet mit diesem Regelsatz nicht neu -rewrite ^ $uri_$args? last;
Jeff Atwood
Fest. Die $ -bleeds-over-the-Variablen fühlen sich an wie PHP, von dem ich weiß, dass Sie es einfach lieben.
CHX
Selbst mit der überarbeiteten Version kann Nginx nicht neu gestartet werden
Jeff Atwood
0

Die oben vorgeschlagenen Antworten sollten funktionieren. Sie sehen jedoch, wie sensibel Ihre URL wird. Da nginx zuerst versucht, zu überprüfen, ob der Dateiname auf dem Server vorhanden ist, wird er durch jeden zusätzlichen Parameter deaktiviert.

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

Mein Vorschlag ist, die URL so zu belassen wie sie ist und sie mit PHP korrekt in die Datei zu leiten. Sie haben Zugriff auf den tParameter.

Ibu
quelle