16

I have this structure: site.com/api/index.php. When I send data to site.com/api/ there is no issue, but I imagine it would be better if the api would work without the trailing slash also, like this: site.com/api. This causes a 301 redirect and thus loses the data (since data isn't forwarded). I tried every re-write I could think of and couldn't avoid the redirect. This is my current re-write rule (though it may be irrelevant).

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^api/(.*)$ api/index.php [L]

Can I make this url work and maintain the post data without using the trailing slash?

Some rewrites that didn't work: (all still redirect)

RewriteRule ^api$ api/index.php [L] 
RewriteRule ^api/*$ api/index.php [L]
m59
  • 43,214
  • 14
  • 119
  • 136
  • The trailing slash is added by the apache module mod_dir: http://httpd.apache.org/docs/2.2/mod/mod_dir.html – Jonathan Kuhn Sep 04 '13 at 23:35
  • Also, your rewrite rule, the way it is written, has the trailing slash as part of the rule. You could probably just remove the `/` from the rule and it would work. – Jonathan Kuhn Sep 04 '13 at 23:38
  • Right. I was thinking that I could rewrite a request to that directory right to index.php so that the module never kicks in, but it didn't work. I'll update to show what I tried there. – m59 Sep 04 '13 at 23:38
  • Where is this .htaccess file located? It would have to be in the parent directory of api. Also, the `!-d` condition would probably have to be removed. that means if the requested file is not a directory and `/api` is a directory so the condition will not match. – Jonathan Kuhn Sep 04 '13 at 23:42
  • It is in the parent directory and I have tried without the conditions. – m59 Sep 04 '13 at 23:43

2 Answers2

13

You'd first need to turn off directory slash, but there's a reason why it is very important that there's a trailing slash:

Mod_dir docs:

Turning off the trailing slash redirect may result in an information disclosure. Consider a situation where mod_autoindex is active (Options +Indexes) and DirectoryIndex is set to a valid resource (say, index.html) and there's no other special handler defined for that URL. In this case a request with a trailing slash would show the index.html file.But a request without trailing slash would list the directory contents.

That means accessing a directory without a trailing slash will simply list the directory contents instead of serving the default index (e.g. index.php). So if you want to turn directory slash off, you have to make sure to internally rewrite the trailing slash back in.

DirectorySlash Off

RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*[^/])$ /$1/

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^api/(.*)$ api/index.php [L]

The first rule ensures that the trailing slash gets appended to the end, though only internally. Unlike mod_dir, which externally redirects the browser, the internal rewrite is invisible to the browser. The next rule then does the api routing, and because of the first rule, there is guaranteed to be a trailing slash.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
  • Is this certainly the only way to avoid the redirect while the module is enabled? – m59 Sep 05 '13 at 00:15
  • Also, is it common for shared hosts to allow this change? I have found them to be strict about certain things like that. – m59 Sep 05 '13 at 00:33
  • 1
    @m59 There is no way to avoid the redirect while mod_dir's `DirectorySlash` is turned on. You can avoid the redirect by turning it off, but mod_dir processes the URI before mod_rewrite does (almost always) so there's no way around it. I don't now how strict hosting services are about this. But `DirectorySlash` is part of the "Indexes" override, so it's most likely they allow that. – Jon Lin Sep 05 '13 at 00:39
  • Should it be `^(.*[^/])$ $1/` without the leading slash? The leading slash was causing me to visit the previous directory. – m59 Sep 05 '13 at 02:31
  • @m59 if your htacces file isn't in your document root, then you don't want the leading slash (your question made it appear that everything was in the document root) – Jon Lin Sep 05 '13 at 02:34
  • 1
    Hmmm. Always more complexity haha. My project needs to be portable. My .htaccess is at the root of the app, but not the document root (at the moment). Whatever I do here, it has to remain functional whether the app folder is at the document root or nested. If you want to save me terrible time of figuring that out, I'd appreciate it, but I can mess with it if I'm asking too much! I'm guessing I'd need to add a condition? – m59 Sep 05 '13 at 03:04
0

If you do not want to use the solution provided by Jon Lin (reconfiguring all your URLs pointing to directories), you could use the following code (note the ? in the regexp - it basically says that the trailing slash after "api" is optional). I have not tested it, but it should work as it is:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^api/?(.*)$ api/index.php [L]
Kleskowy
  • 2,648
  • 1
  • 16
  • 19
  • I did try exactly that. The optional slash doesn't help, nor removing the slash altogether to be certain. – m59 Sep 05 '13 at 00:31
  • I'm pretty sure that doesn't work because the module kicks in and redirects before the rewrite gets a chance to fix it. – m59 Sep 05 '13 at 00:32
  • @m59 I think the reason you were redirected afterwards is because your browser had cached the 301 response, so it automatically redirected to URL with trailing slash. You should test in curl or a fresh browser – Jeff Puckett Oct 03 '17 at 17:25