0

I'm having problem with getting logic behind Nginx rewrites. Are they supposed to be in server or location directive?

I need to rewrite one long and scary URL to another. Is there anyone who can help or at least show me resources to get this done?

Example:

I need to redirect this: http://www.example.com/products.asp?category=Games&product=Glide%20SX%202012%20-%20%20Super%20Partno&utm_source=wcl-ht

into this: http://www.example.com/games/2xu-glid/

Is this even possible?

Thanks for your help.

2
  • 1
    "Context: server, location, if". So it can be both in server and location. The ones are in server are proceeded first.
    – Glueon
    Oct 21, 2014 at 16:45
  • This is such a complex rewrite that I would perform it inside the products.asp script. It requires several if statements when performed in nginx, because nginx rewrite directive doesn't process query arguments. Oct 21, 2014 at 19:24

1 Answer 1

0

1. Handling arguments

Despite what Tero Kilkanen says, nginx is perfectly capable of handling arguments: this is done by using the args and arg_ variables from the core module.

2. rewrite context

As Glueon pointed out, rewrite is usable in server, location and if contexts, as the documentation states.

if is to be avoided at all costs, so I won't be going inot details about it here.

Now should you use rewrite in server or location?

In server

Blocks of rewrites will be considered sequentially, and the first matching will be used. Your configuration thus depends on the order of directives, which is bad (it is one of the things which are wrong with Apache).

See for yourself:

rewrite ^/(?<category>[^/]+)/(?<product>[^/]+) /products.asp?category=$category&product=$product&utm_source=wcl-ht last;
rewrite ^/games/(?<product>[^/]+) /games.asp?product=$product&utm_source=wcl-ht last;

will redirect to products.asp, while

rewrite ^/games/(?<product>[^/]+) /games.asp?product=$product&utm_source=wcl-ht last;
rewrite ^/(?<category>[^/]+)/(?<product>[^/]+) /products.asp?category=$category&product=$product&utm_source=wcl-ht last;

will redirect to games.asp.

According to best practices, it is better to enclose regular expression routing directives (rewrite, but also regex location) inside prefix locations.

In location

You could rewrite the previous examples as

location /games {
    rewrite ^/games/(?<product>[^/]+) /games.asp?product=$product&utm_source=wcl-ht;
}

location / {
    rewrite ^/(?<category>[^/]+)/(?<product>[^/]+) /products.asp?category=$category&product=$product&utm_source=wcl-ht;
}

Using prefix locations, you ensure that whatever ordering you use, the result will always be the same.

3. Minimal configuration

Here is a minimal configuration aiming in the direction of what you wish.

There is no obvious translation rule from 2xu-glid to Glide%20SX%202012%20-%20%20Super%20Partno. If that depends on non-trivial conditions and complex checks, it is probably better to use scripting to do it. Using if inside nginx is dangerous without knowing what you do and could wreak havoc. You can also use a bunch of nested locations to split your translation rules into modular units.

Note that I use a single rewrite here, so it does not need a flag nor does it need to be enclosed in a location. That is because there is only a signle way that configuration might be resolved.

Also note the use of return at the end to ensure no file is ever tried to be served (the default behavior, when no suitable location is found, is to try to serve either a file or index.html from the requested directory, depending on whether the URI ends with /). Since no root is defined, the default internally set would have been used.

events {
    worker_connections  1024;
}


http {
    default_type  text/html;

    server {
        listen       80;

        rewrite ^/(?<category>[^/]+)/(?<product>[^/]+) /products.asp?category=$category&product=$product&utm_source=wcl-ht last;

        location /products.asp {
            internal;
            return 200 "Arguments: $args<br />arg_category: $arg_category<br />arg_product: $arg_product<br />arg_utm_source: $arg_utm_source";
        }

        return 404;
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .