Nginx & Handling Files Without Extension

2019-03-31 04:33发布

问题:

I'm trying to get Nginx to handle php files without an extension (i.e. to handle http://localhost/sample the same way it would handle http://localhost/sample.php).

This is my site configuration:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name localhost;

    root /var/www;
    index index.html index.php;

    location ~ \.(hh|php)$ {
        fastcgi_keep_conn on;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location / {
        try_files $uri $uri/ $uri.html @extensionless =404;
    }

    location @extensionless {
        rewrite ^(.*)$ $1.php last;
    }
}

As far as I know it should do the trick. However - it doesn't. Trying http://localhost/sample just gets me to a 404 page (whereas http://localhost/sample.php works fine).

When turning on debugging, I see the following in the logs:

2015/07/19 15:37:00 [debug] 4783#0: *1 http script var: "/sample"
2015/07/19 15:37:00 [debug] 4783#0: *1 trying to use file: "/sample" "/var/www/sample"
2015/07/19 15:37:00 [debug] 4783#0: *1 http script var: "/sample"
2015/07/19 15:37:00 [debug] 4783#0: *1 trying to use dir: "/sample" "/var/www/sample"
2015/07/19 15:37:00 [debug] 4783#0: *1 http script var: "/sample"
2015/07/19 15:37:00 [debug] 4783#0: *1 http script copy: ".html"
2015/07/19 15:37:00 [debug] 4783#0: *1 trying to use file: "/sample.html" "/var/www/sample.html"
2015/07/19 15:37:00 [debug] 4783#0: *1 trying to use file: "@extensionless" "/var/www@extensionless"
2015/07/19 15:37:00 [debug] 4783#0: *1 trying to use file: "=404" "/var/www=404"

Which is weird. It basically looks like @extensionless is treated as a plain filename (instead of a location leading to a rewrite of the URL).

What am I missing? :) Thanks!

回答1:

    try_files $uri $uri/ $uri.html @extensionless =404;

Yes, @extensionless is treated like a normal file, and that's because you've added an extra =404 after @extensionless within try_files -- the @extensionless part would only work as the last parameter as an internal redirect to another context.

If you want not only to support handing requests without .php, but to also strip .php from any requests, you might want to do the following:

location / {
    if (-e $request_filename.php){
        rewrite ^/(.*)$ /$1.php;
    }
}
location ~ \.php$ {
    if ($request_uri ~ ^/([^?]*)\.php(\?.*)?$) {
        return 302 /$1$2;
    }
    fastcgi_...
}


回答2:

Just updating (in case anyone finds this useful) that I got it to work, eventually.

This is the configuration that did the trick:

server {
    listen 80;

    root /var/www;
    index index.html index.htm index.php;

    server_name localhost;

    location / {
        if (!-e $request_filename){
            rewrite ^(.*)$ /$1.php;
        }
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}


回答3:

It is much better to avoid using slow rewrite and evil IF by the fastest and simplest way:

location ~ ^(.*)\.php$ # If PHP extension then 301 redirect to semantic URL
{
    return 301  $scheme://$server_name$1$is_args$args;
}
location ~ ^/(.*)
{
    try_files $uri.php @static; # If static, serve it in @static
    include fastcgi_params; # if semantic, serve it here
    fastcgi_param SCRIPT_FILENAME $document_root/$1.php;
}
location @static
{
    try_files $uri =404;
}


标签: nginx