How to redirect in nginx if request URI does not contain certain words

aix picture aix · Sep 12, 2017 · Viewed 7.2k times · Source

I'm using nginx to serve static news-like pages. On the top-level there is https://example.com/en/news/ with an overview of the articles. Individual items have a URL similar to this: https://example.com/en/news/some-article

All URLs contain the language, i.e. /en/ or /de/. I would like to create a rule that redirects requests that don't contain the language to the correct URL (the language is mapped based on IP an available via $lang).

The following should work (en example):

/news/             --- redirect ---> /en/news/
/news/some-article --- redirect ---> /en/news/some-article

My attempts looked something like this

location ~* /news/.*$ {
    if ($request_uri !~* /(de|en)/$) {
        return 302 https://example.com/$lang/$request_uri;
    }
}

So far this resulted in infinite redirects.

Answer

Richard Smith picture Richard Smith · Sep 12, 2017

Your solution seems overly complicated to me. And testing $request_uri with a trailing $ will never match the rewritten URIs (hence the loop).

You could use a prefix location to only match URIs that begin with /news/.

Assuming that you have calculated a value for $lang elsewhere, this may work for you:

location ^~ /news/ {
    return 302 /$lang$request_uri;
}

The ^~ modifier is only necessary if you have regular expression location blocks within your configuration that may conflict. See this document for more.