when access url with query string, I want to rewrite to no query string url, like:
/blog/(\d+)/(w+)?a=1$b=2....
rewrite to
/blog/(\d+)/(w+)
If you would like to rewrite all requests a query string, just simply add these to your server block.
if ($query_string != "") {
rewrite ^(.*)$ $uri? last;
}
Explain
The syntax of rewrite directive is
rewrite regex replacement [flag];
First the if statement will match all requests with query strings and rewrite them with the replacement $uri?
According to the documentation, the query strings are dropped because
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended.
Finally the last flag tells nginx to
stop processing the current set of ngx_http_rewrite_module directives and starts a search for a new location matching the changed URI;
Related
I want to rewrite an argument given via URL on my nginx server from "my_arg" to "my-arg". The problem is that I can't know how many arguments there will be in advance nor the position of these arguments.
I can only know if the arguments is there using :
if ($args ~ (.*)my_arg=(.*)) {
rewrite ....
}
But i cannot achieve to only change the name of this argument without changing every others.
Thanks by advance
For anything except HTTP 301/302 redirection you'd better just change an $args variable value:
if ($args ~ (^|.*&)my_arg=(.*)) {
set $args $1my-arg=$2;
}
If you want to generate a redirect, things will be more complicated. Since any rewrite directive performs its own URI matching against some regex pattern, all the $1, $2 and so on variables from previous matching will be overwritten, and you can't match a query part of the URI to get them re-evaluated since rewrite directive works with normalized URI that doesn't include a query part. Your only way is to use named capture groups:
if ($args ~ (?<prefix>^|.*&)my_arg=(?<suffix>.*)) {
rewrite ^ $uri${prefix}my-arg=$suffix? <redirect|permanent>;
}
Trailing question mark used intentionally since as rewrite directive documentation says,
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended, for example:
rewrite ^/users/(.*)$ /show?user=$1? last;
I'd like a single nginx rewrite rule, hopefully in one line of code because I have to make a bunch of these, that can match and redirect either of these:
/short_url
/short_url?utm_source=email
without matching and redirecting:
/short_url/page.html
/short_url/page.html?utm_source=email
And if the query string exists, I want to pass it on.
I was hoping this would work, but no:
rewrite (?i)^/short_url /new_short_url$is_args$args permanent;
What's the secret sauce?
URL params are always passed with rewrite, no need to explicitly declare them in new URL.
## /short_url
## /short_url?utm_source=email
rewrite ^/short_url(\?utm_source=email)?$ /new_uri
I am trying to get an NGINX redirect to take me from:
https://example.com/ui/?outletID=123&setID=456
to:
https://example.com/ui/?outletId=123&setIds=456
So outletID -> outletId AND setID -> setIds
IMPORTANT: I don't know where these params appear inside the URL, so there might be other strings before or after these. I only care for this replacements: outletID -> outletId; setID -> setIds.
This works at first try:
if ($args ~* "^outletID=(\d+)&setID=(\d+)(.*)") {
set $outletid $1;
set $setid $2;
set $everythingelse $3;
set $args '';
rewrite ^.*$ /ui/?outletId=$outletid&setIds=$setid$everythingelse permanent;
}
But it looks like really bad practice and I particularly hate the $everythingelse ($3) solution I ended up with.
To cover all possibilities, you probably need to do this in two stages, one redirect if outletID is present, and another redirect if setID is present.
For example:
if ($args ~ ^(.+&|)outletID(=.*)$) {
return 301 "$uri?${1}outletId$2";
}
if ($args ~ ^(.+&|)setID(=.*)$) {
return 301 "$uri?${1}setIds$2";
}
Per Nginx documentation,
If a replacement string includes the new request arguments, the
previous request arguments are appended after them.
So, in case you don't mind having old outletID and setID hanging around, you could simply do:
rewrite (.*) $1?outletId=$arg_outletID&setIds=$arg_setID permanent;
This way, you'll get something like https://example.com/ui/?outletId=123&setIds=456&outletID=123&setID=456.
But if you would like to have the URLs clean after redirection, Nginx has you covered as well. The excerpt from the same documentation:
If this is undesired, putting a question mark at the end of a replacement string avoids having them appended
Which means, you have to enumerate all the parameters you need to pass. For example, if you have some another possible parameter in query string session, you'll need to include it:
rewrite (.*) $1?outletId=$arg_outletID&setIds=$arg_setID&session=$arg_session? permanent;
Note the ? in the end of replacement string.
Personally I would choose the first approach, because it is less error-prone and will not break your application unexpectedly at the time you added a new parameter.
I'm trying to create a rewrite rule in Nginx to remove trailing slashes.
My rule so far is:
rewrite ^/(.*)/$ /$1;
I want to remove trailing slashes for all URL:s except those that has a query string directly after a trailing slash, how do you do that? I mean URLs that look like https://www.domain.tld/page/?query=xxx
When using rewrite, the query string is appended automatically
From http://wiki.nginx.org/HttpRewriteModule:
If in the line of replacement arguments are indicated, then the rest of the request arguments are appended to them. To avoid having them appended, place a question mark as the last character:
Just an FYI if you are using rewrite for a redirect it is not recommended but no one is going to stop you.
This rule removes trailing slash from url on both cases and worked fine for me; you can customize the the if logic by the way
location ~ (.*)/$ {
if ($query_string) {
return 301 $scheme://$host$1?$query_string;
}
return 301 $scheme://$host$1;
}
I'm going bananas trying to get a Nginx rewrite rule to work. An example URL that the rewrite pattern should match is:
https://test.mydomaind.com/abc.php?id=1
My rewrite rule:
rewrite ^/abc\.php?id=(.*)$ https://test.mydomain.com/page/$1 permanent;
But this returns a 404 with the example URL.
Can anyone tell me what I'm doing wrong? When I leave out the query string parameter in the condition the rewrite does work and the user is redirected 301:
rewrite ^/abc\.php$ https://test.mydomain.com/page permanent; # THIS WORKS
Any help is greatly appreciated!
Anything from the ? onwards is the query string and is not considered when matching the URI to locations or rewrite statements.
The query string (or arguments) are accessible in the $request_uri and $query_string (aka $args) variables and the family of variables prefixed with $arg_.
You could implement something similar with:
location = /abc.php {
return 301 https://test.mydomain.com/page/$arg_id;
}
If you need to test for the presence of an id= argument, you will need to resort to map or if statements.