Règle de réécriture Nginx pour remplacer le point d'interrogation de la chaîne de requête par un trait de soulignement


16

Afin de refléter un site Web entier en HTML statique,

Je voudrais convertir des URL comme http://example.com/script.php?t=12à http://example.com/script.php_t=12.

L'avis ?dans l'URL est en cours de conversion _.

Cela permettra à nginx ou apache de servir ces fichiers à partir du disque en tant que HTML brut que nous avons obtenu et enregistré à partir wget- un fichier pour chaque URL - plutôt qu'en tant que fichier PHP.

Est-il possible de le faire via la réécriture d'URL Nginx?


C'est certainement possible, mais vraiment bizarre. Vous le voulez pour quoi?
Alexey Ten

2
Un problème avec cette approche est que plusieurs paramètres GET dans une URL peuvent être dans n'importe quel ordre, et lorsque vous effectuez cette conversion, vous modifiez la sémantique de l'URL.
Tero Kilkanen

son pour l'archivage d'un ancien forum en html statique, mais oui, avoir ce travail avec http://example.com/script.php?a=1&t=3va nécessiter une action de réécriture super sophistiquée
Sam Saffron

1
@tero les URL de la chaîne de requête sont, dans la pratique, toujours dans le même ordre. Donc, ce n'est pas un problème.
Jeff Atwood

1
@chx il est pour l' archivage d' un ancien forum, si l'argument peut être autre que tcomme f, u, etc.
Arpit Jalan

Réponses:


15

J'ai obtenu ce travail en utilisant try_files:

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

Cela va essayer de trouver un fichier sur le disque nommé d'après le modèle que vous avez fourni avec un "_" au lieu du "?".

La configuration supplémentaire dépend de la façon dont vous avez enregistré des fichiers statiques comme des images ou des feuilles de style. Vous pouvez ajouter une solution de secours en essayant de les lire sans disque de formulaire de chaîne de requête comme ceci:

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

1
approche très intéressante, cela provoquerait-il une lecture potentielle du disque et un "fichier introuvable" sur toutes les URL potentielles?
Jeff Atwood

De try_files : "Vérifie l'existence des fichiers dans l'ordre spécifié et utilise le premier fichier trouvé pour le traitement des demandes". Cela ne provoquera donc aucune lecture de disque supplémentaire pour les URL de votre question.
Matthias Bayer

1
ok, si on le met location ~ \.php$on peut se mettre try_filesau travail, mais ça ne marche paslocation /
Jeff Atwood

+1 par exemple pour utiliser des accolades bouclées :)
Danila Vershinin

4

Quelque chose le long des lignes:

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

Vous avez omis la ?réponse que j'ai utilisée.
chx

Vous avez raison en ce qui concerne?, Quant à votre réponse - il m'a fallu un certain temps pour le tester sur un vrai serveur, donc je n'ai pas vu le vôtre avant d'avoir posté le mien. Et le vôtre réécrira toutes les URL, même sans arguments, avec la variante "_", ce qui peut être indésirable.
Max Gashkov

La solution de Matthias avec try_files est en fait plus préférable à cela.
Max Gashkov

nous pouvons le faire sans le if, lorsque nous spécifions une .*clause plus stricte dans le premier paramètre de réécriture. C'est extrêmement utile!
Jeff Atwood

@JeffAtwood Je ne pense pas que ce soit possible - les modèles de réécriture nginx (ainsi que l'emplacement) devraient s'appliquer à une partie d'une URL avant la chaîne de requête uniquement.
Max Gashkov

1

Je ne pense pas que vous pourrez le faire avec vanilla nginx mais si vous êtes prêt à installer le module Lua pour nginx ( http://wiki.nginx.org/HttpLuaModule ), vous pouvez le faire.

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

    }
}

Testé localement et semble faire ce que vous cherchez. Si vous souhaitez conserver les autres paramètres séparés par des esperluettes, changez le bloc rewrite_by_lua en

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

Cela fonctionne sur nginx / 1.6.2.

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

Mais personnellement, j'utiliserais une try_filessolution avec un retour à un URI d'origine s'il y en a .

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

Par exemple, si vous avez script.phpsur le disque, il essaiera d'abord, puis s'il n'y en a pas, il ira pour script.php_t=12. try_filesa besoin d'une version assez récente de nginx.

Et si cela ne suffit pas, vous pouvez faire ceci dans un if:

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

J'aime, mais nous ne pouvons pas obtenir les try_files bit à fait le travail, alors que la réécriture fait le travail. (eh bien, si vous ajoutez un ?à la fin de votre réécriture là-bas pour que les paramètres de requête n'y soient pas ajoutés.)
Jeff Atwood

@JeffAtwood try_filesva s'arrêter $uris'il y a un bloc d'emplacement correspondant à cela, ou un fichier pour cela (la demande sans obtenir d'arguments) - est-ce le cas?
AD7six

@JeffAtwood ?n'a aucun effet visible sur les fichiers statiques, vous ne verriez qu'une requête supplémentaire dans vos journaux d'accès; si vous vous en souciez, ajoutez un point d'interrogation
sanmai

0

Le wiki dit

Si vous spécifiez un? à la fin d'une réécriture, Nginx supprimera les $ args (arguments) d'origine.

Alors ça rewrite ^ ${uri}_$args? last;devrait marcher.


nginx ne parvient pas à redémarrer avec cet ensemble de règles -rewrite ^ $uri_$args? last;
Jeff Atwood

Fixé. Le $ -bleeds-over-the-variables ressemble à PHP que je sais que vous adorez.
chx

même avec la version révisée, nginx ne redémarre pas
Jeff Atwood

0

Les réponses suggérées ci-dessus devraient fonctionner. Cependant, vous voyez à quel point votre URL devient sensible. Étant donné que nginx essaie de vérifier si le nom de fichier existe d'abord sur le serveur, tout paramètre supplémentaire le supprimera.

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

Ma suggestion est de laisser l'URL telle quelle et de la router vers le fichier correct avec php. Vous avez accès au tparamètre.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.