How to make a rewrite rule of "Redirect Trailing Slashes If Not A Folder."


(fanybook) #21

i want to strip the trailing slash from the PHP index, redirect when {uri} ends_with / and /index.php?{1} exists.

but now, {rewrite_uri} is /index.php?{1}, so redirect to abc.com/index.php?xxxxxxx
my expectation is abc.com/xxxxxxx


(Matthew Fay) #22

This is very confusing… Firstly,

Whether or not /index.php?{1} exists is not a meaningful question. It’s the last rewrite target, it only gets used if the prior rewrite targets fail, in which case it is always used.

Secondly,

This sounds like you want to redirect the client to the PHP index, but…

This kinda makes it sound like you don’t want to redirect the client, you just want to serve the index on that URL.

Which one is the desired behaviour?


At the moment, I’m seeing two different requirements:

  1. If the client requests an existing file, but with a trailing slash, redirect them to remove the slash.
  2. If they don’t request an existing file, (redirect? don’t redirect?) them to the index file.

(fanybook) #23

↑↑ This means that abc.com/xxxxxxx/ should be rewrited to /index.php?{1} (final url is abc.com/xxxxxxx after rewrite & redir, without the /index.php?)

now final url is abc.com/index.php?xxxxxxx after rewrite & redir, has the /index.php?, not my expectation.


like below, abc.com/yyyyyyyyy was rewrited to /index.php?{uri}, final url is still abc.com/yyyyyyyyy

rewrite {
    to {uri} /index.php?{uri}
}

(Matthew Fay) #24

So, these two, then:

  1. If the client requests an existing file, but with a trailing slash, redirect them to remove the slash.
  2. If they don’t request an existing file, serve them to the index file without redirecting.

Lets refactor a bit, then. Try something like this.

# Check for:
# 1. File without trailing slash (like -f)
# 2. Existing directory (like -d)
# Else, fall back to PHP index
rewrite {
  r ^(.+?)/?$
  to {1} {1}/ /index.php?{1}
}

# If we got a request with an unneeded
# trailing slash, redirect the client
# - don't redirect PHP index, though
redir {
  if {uri} ends_with /
  if {rewrite_uri} not_ends_with /
  if {rewrite_uri} not_starts_with /index.php?
  / {rewrite_uri}
}

(fanybook) #25

merge the origin ① and ②

without effect, abc.com/xxxxxxx/'s final url is still abc.com/xxxxxxx/ after rewrite.
no redir,because of if {rewrite_uri} not_starts_with /index.php?.
because the value of {rewrite_uri} is abc.com/index.php?xxxxxxx after rewrite.


(Matthew Fay) #26

Yep, figured there’s no point keeping them separate, Caddy will be running a regex match on every request anyway and it’s simpler this way.

This should only happen if there isn’t a valid file on disk, but there is a valid directory.

Is that not the case?

Yes, that’s by design - you said you don’t want a redirect here? You want this:


(fanybook) #27

my requirement is: [“Romove Trailing Slashes If Not A Folder.”]

only discuss the php index exists. because I already know how to do it in non-php case.

case① : hasn’t trailing slashes:
url abc.com/auth/login should be rewrite to /index.php?/auth/login, final url is still abc.com/auth/login
can via:

rewrite {
    to {uri} /index.php?{uri}
}

it can work.

case② : has trailing slashes:
url abc.com/auth/login/ should be rewrite to /index.php?/auth/login, final url should be abc.com/auth/login (should not be abc.com/index.php?/auth/login). How to do it?


(Matthew Fay) #28

The Caddyfile example I gave in this post satisfies your requirements as best as I can tell. I set it up locally and ran a few test requests against it:

127.0.0.1 - [12/Oct/2018:17:58:19 +1000] "GET /auth/login HTTP/1.1" 404 14 - /index.php?/auth/login

(/auth/login is rewritten to /index.php?/auth/login and not redirected (no 301 response) - it 404s because I haven’t actually made an index file in my test setup)

127.0.0.1 - [12/Oct/2018:17:58:23 +1000] "GET /auth/login/ HTTP/1.1" 404 14 - /index.php?/auth/login

(again, rewritten to /index.php?/auth/login but not redirected - final URL is exactly what the client requested, unchanged)

This is identical behaviour between both requests, trailing slash or no. It does the same thing as to {uri} /index.php?{uri} will do (except that it has the added behaviour of redirecting requests to a file if there’s an extra trailing slash, as requested).


(fanybook) #30

i hope redirect the url from abc.com/auth/login/ to abc.com/auth/login, not to abc.com/index.php?/auth/login (<- current result)

Why redir depends on rewrite?
Why redir can’t use regexp? (can’t use {1})
now i can’t remove the index.php? from {rewrite_uri}


review the apache rule

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

not dir, has trailing slashes, redir, stop match below rule


(Matthew Fay) #31

OK, so I think that you want to redirect to remove the trailing slash, THEN serve the PHP index from the redirected location. Lets try a twist on a previous approach…

  rewrite {
    r ^(.+)/$
    to {1}/ {1}
  }

  rewrite {
    to {path} {path}/ /index.php?{uri}
  }

  redir {
    if {uri} ends_with /
    if {rewrite_uri} not_ends_with /
    / {rewrite_uri}
  }

The result:

127.0.0.1 - - [14/Oct/2018:01:17:57 +1000] "GET /stuff/ HTTP/1.1" 301 0 - /stuff
127.0.0.1 - - [14/Oct/2018:01:17:57 +1000] "GET /stuff HTTP/1.1" 404 14 - /index.php?/stuff

(Again the 404 from the index file because I didn’t put one in to test with)

The only difference from much, much, much earlier in the thread is that I reversed the original rewrite targets. Now it first checks for an existing folder, and if that doesn’t exist, falls back to stripping the slash.


(fanybook) #33

Can you support my requiements? I need 301 not 404


(Matthew Fay) #34

Have a look at my previous post.

It 301’s to remove the trailing slash, then serves the PHP index… Which meets your requirements as you’ve communicated them.

The 404 only occurred in my own tests, because I didn’t put a file there to test with. If you had a PHP index, it would be served.