Regola di riscrittura di Nginx per sostituire il punto interrogativo di querystring con trattino basso


16

Per rispecchiare un intero sito Web come HTML statico,

Vorrei convertire gli URL come http://example.com/script.php?t=12a http://example.com/script.php_t=12.

L'avviso ?nell'URL viene convertito in _.

Ciò consentirà a nginx o apache di servire questi file dal disco come HTML non elaborato che abbiamo ottenuto e salvato da wget- un file per ciascun URL - anziché come file PHP.

È possibile farlo tramite la riscrittura degli URL di Nginx?


È certamente possibile, ma davvero strano. Per cosa lo vuoi?
Alexey Ten,

2
Un problema con questo approccio è che più parametri GET in un URL possono essere in qualsiasi ordine e quando si esegue questa conversione, si modificherà la semantica dell'URL.
Tero Kilkanen,

è per l'archiviazione di un vecchio forum in HTML statico, ma sì, avere questo lavoro http://example.com/script.php?a=1&t=3avrà bisogno di qualche azione di riscrittura super fantasiosa
Sam Saffron

1
@tero gli URL di querystring sono, in pratica, sempre nello stesso ordine. Quindi questo non è un problema.
Jeff Atwood,

1
@chx è per l'archiviazione di un vecchio forum, per cui l'argomento può essere diverso da tcome f, ue così via
Arpit Jalan

Risposte:


15

Ho funzionato usando try_files:

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

Questo proverà a trovare un file sul disco che prende il nome dal modello che hai fornito con un "_" anziché "?".

Un'ulteriore configurazione dipende da come hai salvato i file statici come immagini o fogli di stile. È possibile aggiungere un fallback cercando di leggerli senza la stringa di query dal disco in questo modo:

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

1
approccio molto interessante, ciò causerebbe la lettura di un potenziale disco e il "file non trovato" su tutti i potenziali URL?
Jeff Atwood,

Da try_files : "Verifica l'esistenza dei file nell'ordine specificato e utilizza il primo file trovato per l'elaborazione della richiesta". Pertanto, ciò non provocherà letture aggiuntive del disco per gli URL nella tua domanda.
Matthias Bayer,

1
ok, se lo location ~ \.php$inseriamo possiamo andare try_filesal lavoro, ma non funzionalocation /
Jeff Atwood

+1 per esempio sull'uso delle parentesi graffe :)
Danila Vershinin,

4

Qualcosa del genere:

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

Hai lasciato fuori la ?mia risposta usata.
chx,

Hai ragione riguardo a?, Per quanto riguarda la tua risposta, mi ci è voluto del tempo per testarlo su un server reale, quindi non ho visto il tuo fino a quando non ho pubblicato il mio. E il tuo riscriverà tutti gli URL anche senza argomenti alla variante con "_" ciò che potrebbe essere indesiderabile.
Max Gashkov,

La soluzione di Matthias con try_files è in realtà più preferibile a questo.
Max Gashkov,

possiamo farlo senza if, quando specifichiamo una .*clausola più rigorosa nel primo parametro di riscrittura. Questo è estremamente utile!
Jeff Atwood,

@JeffAtwood Non credo sia possibile: i pattern di riscrittura (così come la posizione) di nginx dovrebbero applicarsi a una parte di un URL prima della sola stringa di query.
Max Gashkov,

1

Non penso che sarai in grado di farlo con nginx alla vaniglia, ma se sei disposto a installare il modulo Lua per nginx ( http://wiki.nginx.org/HttpLuaModule ) puoi farlo.

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

    }
}

Provato localmente e sembra fare quello che stai cercando. Se vuoi mantenere altri parametri separati da e commerciali, modifica il blocco rewrite_by_lua in modo che sia

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

Funziona su nginx / 1.6.2.

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

Ma personalmente userei la try_filessoluzione con un fallback a un URI originale se ce n'è .

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

Ad esempio, se hai un script.phpdisco, ci proverà prima e poi, se non ce n'è, andrà per script.php_t=12. try_filesha bisogno di una versione abbastanza recente di nginx.

E se questo non è abbastanza, puoi fare così all'interno di un if:

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

Mi piace questo, ma non possiamo ottenere il try_files po 'per davvero il lavoro, mentre la riscrittura fa lavoro. (beh, se aggiungi un ?alla fine della tua riscrittura lì in modo che i parametri della query non vengano aggiunti ad esso ..)
Jeff Atwood

@JeffAtwood try_filessi fermerà $urise c'è un blocco di posizione corrispondente o un file per esso (la richiesta senza get args) - è così?
AD7,

@JeffAtwood ?non ha alcun effetto visibile sui file statici, vedresti solo una query aggiuntiva nei tuoi log di accesso; se ti interessa, aggiungi sicuramente un punto interrogativo
sanmai

0

La wiki dice

Se si specifica un? alla fine di una riscrittura, Nginx rilascerà l'originale $ args (argomenti).

Quindi rewrite ^ ${uri}_$args? last;dovrebbe funzionare.


nginx non si riavvia con quel set di regole -rewrite ^ $uri_$args? last;
Jeff Atwood

Fisso. Il $ -bleeds-over-the-variabili sembra PHP che so che ami.
chx,

anche con la versione rivista, nginx non si riavvia
Jeff Atwood il

0

Le risposte suggerite sopra dovrebbero funzionare. Tuttavia vedi quanto diventa sensibile il tuo URL. Poiché nginx tenta di verificare se il nome del file esiste prima sul server, qualsiasi parametro aggiuntivo lo eliminerà.

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

Il mio consiglio è di lasciare l'URL così com'è e instradarlo nel file corretto con php. Hai accesso al tparametro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.