nginx url rewriting: difference between break and last
I don't understand the difference between break and last (flags of rewrite). The documentation is rather abstruse. I've tried to switch between the two in some of my configs, but I couldn't spot any difference in behavior. Can someone please explain these flags in more detail? Preferably with an example that shows different behavior when flipping one flag to another.
Solution 1:
You may have different sets of rewrite rules for different locations. When rewrite module meets last
, it stops processing the current set and the rewritten request is passed once again to find the appropriate location (and the new set of rewriting rules). If the rule ends with break
, the rewriting also stops, but the rewritten request is not passed to another location.
That is, if there are two locations: loc1 and loc2, and there's a rewriting rule in loc1 that changes loc1 to loc2 AND ends with last
, the request will be rewritten and passed to location loc2. If the rule ends with break
, it will belong to location loc1.
Solution 2:
OP preferred an example. Also, what @minaev wrote, was only a part of the story! So, here we go...
Example 1: No (break or last) flags
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
rewrite ^/([^/]+.txt)$ /notes/$1;
rewrite ^/notes/([^/]+.txt)$ /documents/$1;
}
Result:
# curl example.com/test.txt
finally matched location /documents
Explanation:
For rewrite
, the flags are optional!
Example 2: Outside location block (break or last)
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
rewrite ^/([^/]+.txt)$ /notes/$1 break; # or last
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
Result:
# curl example.com/test.txt
finally matched location /notes
Explanation:
Outside the location block, both break
and last
behave in the exact manner...
- no more parsing of rewrite conditions
- Nginx internal engine goes to the next phase (searching for
location
match)
Example 3: Inside location block - "break"
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
rewrite ^/([^/]+.txt)$ /notes/$1 break;
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
}
Result:
# curl example.com/test.txt
finally matched location /
Explanation:
Inside a location block, break
flag would do the following...
- no more parsing of rewrite conditions
- Nginx internal engine continues to parse the current
location
block
Example 4: Inside location block - "last"
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
rewrite ^/([^/]+.txt)$ /notes/$1 last;
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
location /notes {
echo 'finally matched location /notes';
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed, either!
}
location /documents {
echo 'finally matched location /documents';
}
}
Result:
# curl example.com/test.txt
finally matched location /notes
Explanation:
Inside a location block, last
flag would do the following...
- no more parsing of rewrite conditions
- Nginx internal engine starts to look for another location match based on the result of the
rewrite
result. - no more parsing of rewrite conditions, even on the next location match!
Summary:
- When a
rewrite
condition with the flagbreak
orlast
matches, Nginx stops parsing any morerewrites
! - Outside a location block, with
break
orlast
, Nginx does the same job (stops processing anymore rewrite conditions). - Inside a location block, with
break
, Nginx only stops processing anymore rewrite conditions - Inside a location block, with
last
, Nginx stops processing anymore rewrite conditions and then starts to look for a new matching oflocation
block! Nginx also ignores anyrewrites
in the newlocation
block!
Final Note:
I missed to include some more edge cases (actually common problem with rewrites, such as 500 internal error
). But, that'd be out of scope of this question. Probably, example 1 is out of scope, too!