htaccess rewrite causes 500 error instead of 404

2019-02-18 19:41发布

问题:

I've recently added this little bit of code to my .htaccess file:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [L,QSA]

Ok, I understand what's happening here, I think. This little bit of code to remove PHP file extensions causes a loop if the document is not found. This loop causes a 500 server error instead of the (proper) 404. Unfortunately I have very little understanding of what these rewrites are actually doing, so I don't know how to rewrite it to only trigger this redirect if the document exists.

I've done some reading and I'm not sure what Apache considers a "regular" file. I mean it works, but why wouldn't the first line be -f instead of !-f? Is -u the only way to accomplish this?

回答1:

You should test if new path points to an existing file:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [L,QSA]

Otherwise you will get an infinite recursion (error 500).



回答2:

The intention of these rules is, as you suggested, to allow someone to request a page without including the PHP extension. So if you had a file on example.com called about.php then someone would be able to use the URL http://example.com/about in order to access it.

However if someone requests http://example.com/about.php directly you don't want it to be rewritten as http://example.com/about.php.php. Similarly, you don't want requests for images, CSS stylesheets etc to be rewritten. This is where the 2 RewriteConds come in, they are conditions saying that the rewriting should only take place if the request doesn't match a file (!-f) or directory (!-d) that actually exists on the site.

To answer why you're getting a 500, this could be because the permissions in Apache are configured not to allow rewrite rules in an htaccess file or one of several other reasons. Check the end of your error_log to see if there are any messages in there.



回答3:

First off, here is some reference to better understand the mod_rewrite module:

mod_rewrite Documentation

mod_rewrite Cheat Sheet

The problem you are seeing is that it is checking for both conditions, the default is [AND], when you only want to check for one, try this:

RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [L,QSA]