dynamicly handling request which match a location block

This commit is contained in:
AD7six 2014-10-23 15:14:19 +00:00
parent 8934017c17
commit 804ac371bc
2 changed files with 211 additions and 2 deletions

View File

@ -13,10 +13,217 @@ Depending on the server architecture, it's possible to get the following error:
Nginx uses [hash tables](http://nginx.org/en/docs/hash.html) to speed up certain Nginx uses [hash tables](http://nginx.org/en/docs/hash.html) to speed up certain
tasks, usually the default value is sufficient but depending on the actual server tasks, usually the default value is sufficient but depending on the actual server
config this error might be encountered. The solution is to do exactly what the config this error might be encountered. The solution is to do exactly what the
error message suggests, but adding to nginx.conf the following: error message suggests, by adding to nginx.conf the following:
# add this to the http context # add this to the http context
types_hash_max_size: 1024; types_hash_max_size: 1024;
## OR add this to the http context, don't need both ## OR add this to the http context, don't need both
# types_hash_bucket_size: 32 # types_hash_bucket_size: 32
## Only some rules are being applied
Nginx only uses one location block when processing a request.
A direct concequence of this is that if, either directly or via include
statemtents, directives are defined like so:
# Make sure js files are served with a long expire
location ~* \.js$ {
add_header "section" "long expire"; # for illustration only
expires 1y;
}
# Oh, and kill etags for js files
location ~* \.js$ {
add_header "section" "no etags"; # for illustration only
etag off;
}
_the section headers are only to demonstrate which location blocks applied to a
particular request_.
Only ONE of these location blocks will be used:
$ curl -I "http://nginx.h5bp.dev/js/main.js"
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 23 Oct 2014 09:58:47 GMT
Content-Type: application/javascript; charset=utf-8
Content-Length: 1
Last-Modified: Tue, 29 Oct 2013 15:17:17 GMT
Connection: keep-alive
ETag: "526fd17d-1"
Expires: Fri, 23 Oct 2015 09:58:47 GMT
Cache-Control: max-age=31536000
section: long expire
Accept-Ranges: bytes
The way to achieve the desired effect is to consolidate all rules into one
location block:
location ~* \.js$ {
# Make sure js files are served with a long expire
add_header "section" "long expire"; # for illustration only
expires 1y;
add_header "section" "no etags"; # for illustration only
etag off;
}
Which would then yield:
$ curl -I "http://nginx.h5bp.dev/js/main.js"
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 23 Oct 2014 10:00:22 GMT
Content-Type: application/javascript; charset=utf-8
Content-Length: 1
Last-Modified: Tue, 29 Oct 2013 15:17:17 GMT
Connection: keep-alive
Expires: Fri, 23 Oct 2015 10:00:22 GMT
Cache-Control: max-age=31536000
section: long expire
section: no etags
Accept-Ranges: bytes
## Cannot dynamically serve <file extension> requests
It might be expected that a request for a file that does not exist
will always reach the backend application - but this is not necessarily
the case.
Using php as an example, here is a simple example config:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
With the above config, a request for `/css/main.css`, assuming the file exists,
would be served directly by nginx whereas a request for `/application/user.css`
would be processed by php.
it is tempting to add h5bp's basic ruleset by simply appending it in
the server context:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location / {
try_files $uri $uri/ /index.php;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}
# ADDED
include h5bp/basic.conf;
}
The result in this case would be `/css/main.css`, assuming the file exists,
is served with headers defined by h5bp's basic ruleset whereas `/application/user.css`
will be a 404. The reason for this is that H5bp's basic ruleset includes, for example:
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
Which will _also_ capture any dynamic requests matching that url pattern and not
hand the request to the php application in the event of an error.
There are 3 basic strategies to resolve this:
## Define error_page in each location block
Modifying (all) location blocks as follows:
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
error_page 404 = /index.php;
expires 1M;
access_log off;
add_header Cache-Control "public";
}
Will make Nginx pass requests for files that don't exist to the application.
## Use prefix routing
Prefix routing is always preferred - if there is a common path for static files
this can be used to reduce the scope of any included rules:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# ADDED. Apply only to the css, js and images folder
location ~ ^/(css|images|js)/ {
include h5bp/basic.conf;
}
}
## Change to use a 404 front-controller
Instead of using try_files alone, change the server config such that the
application is the 404 page:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
try_files $uri $uri/ @app;
error_page 404 = @app;
location @app {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param SCRIPT_NAME $document_root/index.php;
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_index index.php;
}
# ADDED.
include h5bp/basic.conf;
}
_with this kind of setup it's necessary to explicitly define the php filename_.
In this way after nginx has tried to server a (none existant) static file, it
will pass the request to the php application successfully.

View File

@ -11,7 +11,9 @@ which may trip up new users.
## Nginx will only use one location block ## Nginx will only use one location block
A [location block (directive)](http://nginx.org/en/docs/http/ngx_http_core_module.html#location) A [location block (directive)](http://nginx.org/en/docs/http/ngx_http_core_module.html#location)
defines the behavior for a given request which matches the location url pattern. defines the behavior for a given request which matches the location url pattern. The block used
is whichever is the most specific for the given request, the rules for
precedene can be found in [Nginx's wiki](http://wiki.nginx.org/HttpCoreModule#location).
It is very important when writing nginx configuration files to understand that It is very important when writing nginx configuration files to understand that
only one location block will be used by Nginx. When in doubt a useful technique only one location block will be used by Nginx. When in doubt a useful technique