I need to ensure that all permalinks on a given site end with a trailing slash. That is, any URL that refers to a location that doesn't correspond to an actual, individual file. I also need to preserve any query strings and/or anchors that are passed with the URL.
Example
Say I have a page at the following location:
example.com/about/
If I get the following requests, I want them to rewrite as shown:
example.com/about > example.com/about/
example.com/about?src=fb > example.com/about/?src=fb
example.com/about#contact > example.com/about/#contact
example.com/about#contact?src=fb > example.com/about/#contact?src=fb
However, I want to make sure that I do not rewrite for any actual file paths - anything with a file extension.
What I have so far
This is the regex I have come up with thus far, which only addresses excluding real file paths, and adding a trailing slash when the end of the string doesn't have one:
^([^\.]*$(?<!\/))
I have not yet been able to figure how how to determine whether a trailing slash is present when there are anchors or query strings, and once that's established how to separately capture the parts that should be before the trailing slash and after it in order to assemble the final rewrite.
As it turns out, the regex I came up with does in fact address all of my rewrite needs. Here is the final result in my Nginx server configuration:
location / {
try_files $uri $uri/ #rewrites;
}
# Rewrite rules to sanitize and canonicalize URLs
location #rewrites {
rewrite ^([^\.]*$(?<!\/)) $1/ last;
}
Related
I have some URLs like:
http://example.com/username/file.zip
http://example.com/username/videos/aaa.avi
http://example.com/username/videos/abc/asdfdef/aaa.avi
the real path of files are:
/file.zip
/videos/aaa.avi
/videos/abc/asdfdef/aaa.avi
so basically I need to remove first folder in the URL
I tried to use this rewrite rule :
rewrite ^/.*/(.*)$ /$1 last;
but its remove all folders and grep just the filename, it's work just for first URL and i get 404 error for rest of them
- P.S: the username could be anything
i didnt test it but based on that nginx uses pcre library i think
rewrite ^/.*?/(.*)$ /$1 last;
would work.
.*? matches any character between zero and unlimited times, as few times as possible, expanding as needed (lazy)
I want to check if a parameter is present in a url in nginx and then rewrite. How can i do that?
The color is dynamic in the URLs
For e.g
If url is http://website.com/lunch-box/xxxxxabc then redirect user to http://website.com/lunch-box/.
If URL is http://website.com/lunch-box/xxxxxabc/ABCD123 no need to redirect. Need to load as it is.
I want to redirect if URL is matched. and xxxxxabc is dynamic text.
nginx version: nginx/1.16.1
# rewrite direct children of /lunch-box but not grandchildren+
rewrite ^(/lunch-box/)[^/]+/?$ $1 last;
Walking through the regex ^(/lunch-box/)[^/]+/?$
^ matches the start of a string (rewrite rules match against the path, not the full URI)
(/lunch-box/) matches the literal text /lunch-box/ and saves it for $1
[^/]+ matches one or more characters that are not a forward slash
/? matches zero or one forward slash
$ matches the end of the string
This strips off the path past what we've saved as $1, but only when that path is a direct child.
I have to add a trailing slash in the url that refers to a location that doesn't correspond to an actual, individual file. For e.g:
http://example.com/Myapp/42.5.01/Mobile.zip
Here i have in the url the version of the application which has ".' for e.g 42.5.01. So when i have the below regular ex:
rewrite ^([^.]*[^/])$ $1/ permanent;
This is ignoring to put the trailing slash after 42.5.01. Hence we are not able to access/download the Mobile.zip.
The Trailing slash should not be for individual file only.
The file can be a ".tar", ".war", or a ".zip"
How do i make sure the trailing slash is for the version but not for the application.
You can use a regular expression with a negative lookahead assertion to match some patterns but ignore other patterns. For example, to match URIs which do not end with a / character and ignore URIs that end with a 3 or 4 character extension, you could use:
rewrite "^/(?!.*\.[A-Za-z]{3,4}$).*[^/]$" $uri/ permanent;
The first part (?!.*\.[A-Za-z]{3,4}$) is a negative lookahead. See this document for details.
Alternatively, you can use break in a rule to stop rewrite processing before your rule is reached, for example:
if ($uri ~ "\.[A-Za-z]{3,4}$") { break; }
rewrite "[^/]$" $uri/ permanent;
Or:
rewrite "\.[A-Za-z]{3,4}$" $uri break;
rewrite "[^/]$" $uri/ permanent;
See this document for details.
Finally, depending on the structure of your configuration file, you may be able to use location blocks to limit the scope of the rewrite. For example:
location / {
return 301 $uri/;
}
location ~ "\.[A-Za-z]{3,4}$" {
...
}
location ~ /$ {
...
}
The above is likely to break any non-trivial configuration as Nginx chooses a single location block to process a request and the presence of other location blocks will interfere with the logic.
location ~ ^/random/?$ {
try_files $uri $uri/ /api/random.php;
}
I have this rule in my nginx config file and I want to be able to call this URL like /random or /random/
The problem is that this rule allows infinte trailing slashes at the end like /random///// for ex. will also work.
nginx uses a normalised URI when matching location directives, so multiple consecutive /s have already been reduce to a single / by the time your regular expression is tested.
You could reject multiple consecutive /s by testing the $request_uri variable, which contains the original URI together with query string (if any). For example:
if ($request_uri ~ //) { return 403; }
I have the following rewrite rule in my nginx:
rewrite ^/(.*)/$ /$1 permanent;
to remove trailing slash at the end of any URL. However I wanted to make an exception such that when the URL is /register/ I don't want this rule to be applied. How do I put that into the regex?
You can use a Negative Lookahead.
^/(?!register)(.*)/$
If you don't want register anywhere between such as /exampleregister/, use the following.
^/(?!.*register)(.*)/$