RewriteCond %{REQUEST_URI} !-f
Which confirms the request is not for a file (you can do !-d to exclude directories). Much simpler than faffing with extensions.
The default for R is 302 already (so just [L,R] will do), but you possibly want 301 (permanent change) instead (although also best to wait until the rule works before doing that, to prevent browsers being annoying.)
If that still errors, see if you've got a log file giving any messages (might be mod_rewrite specific or in the Apache-wide error_log) - nothing is jumping out at me, but I am tired enough to potentially miss something obvious.
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !^/index.html$ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L]And I (then) got it appending the url as a hash (replacing last line above):
RewriteRule ^(.+)\.html?$ /index.html#$1 [R,L,NE]This is on a staging server root, not sure if it's going to work on shared hosting though.
RewriteRule ^index\.html - [L] RewriteRule ^(favicon\.ico|robots\.txt)$ - [L]
Where the hyphen says "don't rewrite it".
The reason for having distinct rules being both readability and because despite being written first the rewrite conditions are checked after the first part of the RewriteRule is tested - so it feels better having distinct rules. (There'll be a (probably very minor) performance benefit too.)
I've not had problems with ErrorDocument - it is necessary to set it with cPanel, but all I do is this:
ErrorDocument 404 default ErrorDocument 403 default ErrorDocument 410 default ErrorDocument 500 default
Don't remember if the order is relevant, but I have them after the RewriteEngine On line but before any rules are listed.
HTML5 History stuff is piss easy - just use this: https://github.com/browserstate/history.js/
There should be enough docs/examples/etc there to get it going, but I can probably answer questions if it misses anything.
RewriteRule ^(.+)\.html?$ /index.html#$1 [R,L,NE] RewriteRule ^$ /index.html [R,L]
throws it into a loop.
-----
Edit: hmmm, nope. After fixing a misplaced [L] flag, the htaccess seems to be working fine*. The loop was being caused by a js $.get statement which fails spectacularly (and mysteriously) if an include can't be found, in this case due to a misconfigured path, by 'get-ting' the entire index page instead, even though I was using a jqXHR .fail statement that works fine in other .get instances in my script. I managed to work out a kludge:
if ( !data.match(/^<DOCTYPE/) ) { [do the good stuffs] } else { FOAD }
*on my staging server...
The good thing about history.js is that it plugs in to several common libraries, but also has a native adapter.
Another workaround, if you're receiving a full page instead of a segment, is to pull out the html from the main content div, along the lines of:
if ( data.match(/^i) ) data = $('div#content',data).html();
Not sure if it applies for your situation, but still a useful thing to keep in mind.
More people use Apache then every other web server combined, and it has over twice the usage of the second most common server.
IF nginx continues to gain use at its current rate, it'll be 2020 before it has equal share to Apache.