Reputation: 24954
Should following nginx config be dead cycle?
location / { # url rewrites rewrite ^/(.*).jsp$ /$1.html last; try_files $uri $uri/ =404; }
According to doc it seems should, but in test it seems works the same as:
rewrite ^/(.*).jsp$ /$1.html break;
About last
, nginx doc says:
it start a search for a new location that matches the rewritten URL.
The questions are:
location
directive?location
where the current last
resides, should it stop or .. ?Upvotes: 4
Views: 2420
Reputation: 2811
To explain this, let's take a look at this example configuration:
server {
listen 80;
server_name localhost;
location / { # Location #1
root /some/path;
}
location ~ ^/(foo|bar|baz) { # Location #2
rewrite ^/foo /bar; # Rewrite rule #1
rewrite ^/bar /baz break; # Rewrite rule #2
rewrite ^/baz /qux last; # Rewrite rule #3
rewrite ^/qux /foo; # Rewrite rule #4
root /another/path;
}
}
What happens if we are trying to open http://localhost/foo
in a
browser is this:
Nginx parses the request, gets the URI part (/foo
) and then looks
for all the locations that match this requested URI. In this case
both locations match the URI, but since Location #2
is defined
with a regular expression, Nginx will choose it over Location #1
,
or in other words, will make this location the request context. You
can find some info on the location priorities in the
documentation.
Now that the location is determined, Nginx starts executing all the rewrite directives found in it one by one.
After the Rewrite rule #1
is executed the URI is changed from
/foo
to /bar
and Nginx proceeds with execution of the next
rewrite directive, which is the Rewrite rule #2
.
After the Rewrite rule #2
is executed the URI is once again
changed, this time from /bar
to /baz
. And since the break
flag
is used Nginx won't execute the rest rewrite directives in this
location. So neither the Rewrite rule #3
nor Rewrite rule #4
will be executed this time.
As a result, /another/path/baz
will be shown in the browser.
The same file will be served if we request http://localhost/bar
directly. Only in that case Rewrite rule #1
will not be executed
(because /bar
does not match ^/foo
).
Now if we try to open http://localhost/baz
the process will go
like this:
The Location #2
will be chosen as the context because it is of a
higher priority and matches the request. Both the Rewrite rule #1
and Rewrite rule #2
will be ignored, because /baz
does not match
either ^/foo
or ^/bar
.
The break
flag of Rewrite rule #2
will be ignored along with the
rule itself, because flags affect the process only when URI is being
rewritten by the rule to which the flag belongs.
The Rewrite rule #3
matches the URI and so it will be executed.
The rule changes the URI from /baz
to /qux
and then the whole
process is interrupted because the last
flag kicks in. What it
does is basically tells Nginx to stop processing the request and
start from the very beginning but this time using the rewritten URI.
So Nginx starts looking for a suitable location once again, but this
time the URI is /qux
, not /baz
. And since Location #2
does not
match /qux
, Location #1
is chosen as the request context. And so
/some/path/qux
is served (pay attention to the path).
The most interesting part here is that we started in the context of the Location #2
and ended up in Location #1
because of the last
flag.
This is how it all works. And yes, if there is only one location, it will be used again (providing it matches the rewritten URI), but this time with the new (rewritten) URI. And yes, it is possible to cause an infinite loop with an unfortunate configuration. Although Nginx will detect and interrupt it after 10 cycles or so.
P.S. If you are wondering about Rewrite rule #4
, in this configuration it is a "dead directive". It will never be executed.
Upvotes: 15