Reputation: 23749
Using nginx compiled with Lua support, how can we make a sort of sub-request to a FastCGI handler, much like nginx's fastcgi_pass
directive?
What I'd like to do is something like this:
location = / {
access_by_lua '
res = ngx_fastcgi.pass("backend")
';
}
(Obviously, this doesn't work.)
I'm pouring over HttpLuaModule where I see mention ngx_fastcgi
and ngx.location.capture
, which, evidently, makes
non-blocking internal requests to other locations configured with disk file directory or any other nginx C modules like ... ngx_fastcgi, ...
But then following the link of ngx_fastcgi
takes me to HttpFastcgiModule which explains only nginx directives, not Lua-scriptable commands. Is ngx.location.capture
the right function to use? (These requests, by the way, will be to localhost
, just on a different port, like 9000 or 9001.)
How can I use Lua in nginx to forward a request, or make a sub-request, to a FastCGI endpoint?
Upvotes: 2
Views: 3230
Reputation: 5267
Use the ngx.location.capture() method to perform a subrequest to a predefined location block. Then, from within the location block, perform the external, FastCGI request. Because the subrequest itself isn't actually a network operation, but is performed purely within nginx C-based environment, there's very little overhead. Further, because the FastCGI request and other "proxy_pass"-type requests are event-based, nginx can operate as an efficient intermediary.
As an example, you could have the following:
location / {
access_by_lua '
response = ngx.location.capture("/my-subrequest-handler")
if response.status == 404 then
return ngx.exit(401) -- can't find/authenticate user, refuse request
end
ngx.say(response.status)
';
# other nginx config stuff here as necessary--perhaps another fastcgi_pass
# depending upon the status code of the response above...
}
location = /my-subrequest-handler {
internal; # this location block can only be seen by nginx subrequests
fastcgi_pass localhost:9000; # or some named "upstream"
fastcgi_pass_request_body off; # send client request body upstream?
fastcgi_pass_request_headers off; # send client request headers upstream?
fastcgi_connect_timeout 100ms; # optional; control backend timeouts
fastcgi_send_timeout 100ms; # same
fastcgi_read_timeout 100ms; # same
fastcgi_keep_conn on; # keep request alive
include fastcgi_params;
}
In the above example, even though I'm performing a subrequest to "/my-subrequest-handler", the actual URL passed to the FastCGI process is the one requested by the HTTP client calling into nginx in the first place.
Note that that ngx.location.capture is a synchronous, but non-blocking operation which means that your code execution stops until a response is received, but the nginx worker is free to perform other operations in the meantime.
There are some really cool things that you can do with Lua to modify the request and response at any point in the nginx pipeline. For example, you could change the original request by adding headers, removing headers, even transforming the body. Perhaps the caller wants to work with XML, but the upstream application only understands JSON, we can convert to/from JSON when calling the upstream application.
Lua is not built into nginx by default. Instead it's a 3rd party module that must be compiled in. There's a flavor of nginx called OpenResty that builds in Lua+LuaJIT along with a few other modules that you may or may not need.
Upvotes: 5