FWIIW, I've also looked at the other "weird" answer to the question you link — it was written in 2011, had only 3 upvotes earlier today in 2017, compared to 23 upvotes for the more recent answer circa 2014 that you quote. Perhaps somewhat surprisingly, the older ignored answer does actually work without any issues as well!
Here's my take at the full MVP config, fully tested:
server {
listen 7461;
error_page 429 = @slowdown;
if ($http_x_secret_header != secret_value) {
return 429;
}
location @slowdown {
#limit_...
return 200 "$uri: slowed down\n";
}
location / {
return 200 "$uri: very fast\n";
}
}
Here's the testing to show you that it all works, including the fact that the correct 200 OK
code is returned:
%curl -H "X-Secret-Header: secret_value" localhost:7461/important/path/
/important/path/: very fast
%curl -H "X-Secret-Header: wrong_value" localhost:7461/important/path/
/important/path/: slowed down
%curl -v localhost:7461/important/path/ | & fgrep -e HTTP/ -e /important
> GET /important/path/ HTTP/1.1
< HTTP/1.1 200 OK
/important/path/: slowed down
%
So, yes, the error_page
redirection does actually work, too!
Let me explain the rationale for the weird error_page
answer — in nginx, you can do both external redirects (visible to the client), as well as internal redirects (done internally, without any intermediate replies to the client).
This internal vs. external difference is a very powerful concept, without which many cool tricks wouldn't be possible, since the configuration language is simple enough to limit the number of directives available from within an if
statement, as well as not allow nested if
statements.
So, instead, with the internal redirects, the $uri
can be changed internally, causing your request to bounce around between multiple independent locations (think of each location
as a state in a DFA (deterministic finite automaton)), until a desired result is achieved (for an extreme example of this, take a look at http://mdoc.su/, as seen at nginx.conf 2016).
To summarise, in the example above:
we repurpose the 429
error_page
to act as an internal
redirect to an internal
location
, and then process such internal
location
in the very same way as a non-internal location would have been processed, except for the addition of some additional variables or directives;
we also use the =
parameter to error_page
directive to instruct nginx to not actually send the 429
code back to the client, but instead let the further processing dictate what the final status code should be.