skip to Main Content

So I got a website and set up some htaccess stuff like errordocuments and clean url rewrites.
The problem I’m currently encountering is that the rewrite doesn’t always work and end on my 404 error page.

  • This link works: example.com/texts/2
  • This link works too: example.com/texts/3
  • But this doesn’t: example.com/texts/1
  • This doesn’t work aswell: example.com/texts/4

although it did work yesterday.

I edited some stuff but because it wasn’t working, I reset it to the backup I did before editing so the .htaccess is exactly the same.

The funny thing tho is that if I put everything in a new folder /test/ i.E.
it works just fine.

Now I don’t want to always change the folder and links between the different sites after I edited something in the .htaccess so I would like to know why this problem occurs and how to prevent and fix it.

I did search for like a few hours now and didn’t find anything that comes close to my error.

My .htaccess:

Options +FollowSymLinks
RewriteEngine on

ErrorDocument 403 /index.php?page=403

RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^([a-zA-Z0-9]+)$ index.php?page=$1
RewriteRule ^([a-zA-Z0-9]+)/$ index.php?page=$1
RewriteRule ^texts/([0-9]+)$ index.php?page=texts&id=$1
RewriteRule ^texts/([0-9]+)/$ index.php?page=texts&id=$1

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /404 [L,R=301]

2

Answers


  1. Your browser has cached the 404 redirect rule for those paths that do not work.

    Try emptying the cache of the browser and the problem should go away.

    Login or Signup to reply.
  2. ErrorDocument 403 /index.php?page=403
    
    :
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /404 [L,R=301]
    

    It’s already been identified as a caching issue. But you shouldn’t have been getting a caching issue in the first place if it wasn’t for how you are triggering your 404… you are 301 (permanent) redirecting this to /404 (a virtual URL) that is then further rewritten. This is bad. 301s will be persistently cached by the browser, but you also lose all the information about the URL that triggered the 404 in the first place.

    Why not configure your 404 in the same way you have configured your 403? ie.

    ErrorDocument 404 /index.php?page=404
    

    Which is what a request to /404 would seem to do. However, now you can examine elements of the request to analyse the 404.

    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteRule ^([a-zA-Z0-9]+)$ index.php?page=$1
    RewriteRule ^([a-zA-Z0-9]+)/$ index.php?page=$1
    RewriteRule ^texts/([0-9]+)$ index.php?page=texts&id=$1
    RewriteRule ^texts/([0-9]+)/$ index.php?page=texts&id=$1
    

    Apart from mixing SCRIPT_FILENAME and REQUEST_FILENAME (they refer to the same thing in this context), RewriteCond directives only apply to the first RewriteRule that follows. It looks like they should apply to the first two rules (at least).

    However, those two rules can be combined into one anyway, since you are simply making the trailing slash optional. BUT, if you make the trailing slash optional on an internal rewrite then you are potentially creating "duplicate content". Presumably only one URL is canonical (at least it should be), ie. you are consistently linking to URLs with or without the trailing slash and not both. So, you should only rewrite one of them. If you want to handle both URLs (with and without a trailing slash) then you should externally "redirect" from one to the other.

    For example, favouring URLs without a trailing slash (as in your examples) and redirecting URLs that end in a trailing slash:

    Options +FollowSymLinks
    RewriteEngine on
    
    ErrorDocument 403 /index.php?page=403
    ErrorDocument 404 /index.php?page=404
    
    # Canonical redirect to remove trailing slash from all URLs
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.+)/$ /$1 [R=301,L]
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^([a-zA-Z0-9]+)$ index.php?page=$1
    
    RewriteRule ^texts/([0-9]+)$ index.php?page=texts&id=$1
    

    I also removed the filesystem check for a file, since it’s highly unlikely that a request that matches the regex ^([a-zA-Z0-9]+)$ will map to a real file. Filesystem checks are relatively expensive, so if you don’t need them; don’t use them.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search