nginx and rewriting based on GET-parameter (URL-parameters/arguments)

Update: see the comment below from Alan Orth about how to implement this in a much cleaner way now!

When rewriting URLs in Apache through mod_rewrite, you have the possibility of using RewriteCond to only apply rewrites if the original resource has been called with a particular argument in the URL (such as “/file?oid=..”).

The solution in nginx was however a bit different, but thanks to Rewriting URL-params in nginx I got on the right track from the start.

In nginx this information is available through the $args variable, which will contain the complete query string. In Will’s example above he’ll replace the query string, but I were interested in inserting a specific parameter instead (and include the previous query string, so I couldn’t just do the “set $args ..” that he does in the example).

My first try was to simply use $1 in the rewrite destination, but this didn’t work – as rewrite will reset the captured patterns from the previous regular expression (since the rewrite source also is a regular expression). But by introducing my own, temporary variable I were able to save the value from the matching regular expression (for the GET parameter) and use it in my rewrite destination.

The following example shows how I ended up solving the issue. This will rewrite the URL only if the “oid” parameter is found at the beginning of the query string when the URL is requested, and the location = /oldURL limits the rewrite to requests for the old resource.

location = /oldURL {
    if ($args ~ "^oid=(\d+)") {
        set $key1 $1;
        rewrite ^.*$  /newURL?param1=foo¶m2=bar&key1=$key1 last;
    }
}

This will rewrite a request for /oldURL?oid=123&what=cheese to /newURL?param1=foo&param2=bar&key1=123&oid=123&what=cheese — if you want to exclude the previous arguments, you can either just set $args directly to key1=$1 and just use param1=foo and param2=bar in the rewrite destination:

        set $args key1=$1;
        rewrite ^.*$  /newURL?param1=foo¶m2=bar last;

This might be cleaner, depending on what you’re trying to do.

7 thoughts on “nginx and rewriting based on GET-parameter (URL-parameters/arguments)”

  1. I find solution for handle the query string so long time util I met your blog.

    Thank you very much for your good article :)

  2. Apache rules is more easy to use then nginx, we can use %1, %2 parameters but not with nginx. you solution helps for some case but can not for others. you did a great article and I like it.

    Thank you for this post
    Quran

  3. Thanks Alan, I’ve added a note at the top of the post linking to your comment so people find the Proper Way of doing things now.

  4. Hello Alan,

    Thank you for your post. I know it is an older post and you may or may not respond, however, I thought I would try this route anyway.

    I have old URLs like this one:

    /products_r/product_info.php?cPath=6&products_id=1

    And I need to rewrite the GET values turning ? and & into a /
    I know this is weird but the only way to tell Magento 2 to do a redirect because M2 seems to ignore ?……….. when it comes to URL redirects.

    so I want:
    /products_r/product_info2.php/cPath=6/products_id=1

    So based on your block, would mine look like this?

    location = /products_r/product_info.php {
    set $key1 $arg_cPath;
    set $key2 $arg_products_id;
    rewrite ^.*$ /products_r/product_info2.php/cPath=$key1/products_id=$key2 last;
    }

    By the way I have tried this too:
    rewrite ^.*$ /products_r/product_info2.php/cPath=$arg_cPath/products_id=$arg_products_id last;
    BUT, it seems that nginx omits the $arg_products_id value for some reason and rewrites it to:
    /products_r/products_info2.php/cPath=6/products_id=

    I got another one, and this one seems to work (because mabye there is only one GET variable?)

    location = /products_r/index.php {
    set $key1 $arg_cPath;
    rewrite ^.*$ /products_r/index2.php/cPath=$key1 last;
    }

    Maybe I am doing this all wrong and there is a much better way?

    I am having troubles getting this to work. If you can spare a moment can you help?

    Thanks.

  5. Hi,

    Sorry, I don’t have an answer ready for you. I’d suggest posting it to Stack Overflow – since that’s where all the tech questions live these days :-)

Leave a Reply

Your email address will not be published. Required fields are marked *