You can probably combine rewrite and redir, I think… Try something like this:
# First we rewrite, trying
# the request without the
# trailing slash in case it's
# actually a file.
rewrite {
regexp ^(.+)/$
to {1} {1}/
}
# Then, if the request ended
# in a slash, but the rewrite
# didn't, redirect to the new URI
redir 301 {
if {uri} ends_with /
if {rewrite_uri} not_ends_with /
/ {rewrite_uri}
}
After this rewrite, if the path is invalid, {rewrite_uri} will be /index.php?/api/circle/group?limit=2.
The query is everything after the first ? and before any anchors. In this case, {query} is /api/circle/group?limit=2.
You can effectively test these for yourself by adding log / stdout "{uri} {rewrite_uri} {path} {query}" or similar to your Caddyfile (adding or removing placeholders as you need), initiating requests, and observing the output from Caddy.
{host}/index.php?/api/circle/group?limit=2 can't work
but
after rewrite
{host}/api/circle/group?limit=2 can work
I think the {query} is limit=2, {uri} is /api/circle/group?limit=2, {path} is /api/circle/group
If what I think is right, /index.php?{query} is ’/index.php?limit=2’
In this case, if {query} is /api/circle/group?limit=2, rewrite to /index.php?/api/circle/group?limit=2 should can’t work, because of two ?
Sorry, yes, this is a correct assessment for the given request /api/circle/group?limit=2.
My above post was the results from a request for /index.php?/api/circle/group?limit=2.
No, the second ? won’t interfere. There can be question marks in the {query} placeholder. The first question mark is regarded as the beginning of the query, and it ends only at the end of the URI or the start of the fragment #.
# First we rewrite, trying
# the request without the
# trailing slash in case it's
# actually a file.
rewrite {
regexp ^(.+)/$
to {1} {1}/
}
# Then, if the request ended
# in a slash, but the rewrite
# didn't, redirect to the new URI
redir 301 {
if {uri} ends_with /
if {rewrite_uri} not_ends_with /
/ {rewrite_uri}
}
if rewrite’s result is 404, redir wasn’t executed.
Yes, that is the expected behaviour of that configuration.
That redirect only ever takes place if the client requested a URL with a trailing slash, but the rewrite found a file without the trailing slash was present.
If there’s no file (i.e. a 404 would be generated), the rewrite falls back to the originally-requested URI, and if that URI doesn’t exist, the file server will naturally return the 404.
The Caddyfile example you posted, however, has a second rewrite. That rewrite will only ever occur if the first rewrite’s regex isn’t matched - that is, it’ll only work on requests that don’t end in a trailing slash.
If you want your first rewrite to also fall back to /index.php?{query}, you’ll need to add it to the list of targets on the first rewrite.
eg. xxx.com/abc/ddddddd/
this url with a trailing slash, there’s no file, but php route is exist.
① match it,{rewrite_uri} is xxx.com/index.php?/abc/ddddddd
③ match it, this url is redirected, the new url is xxx.com/index.php?/abc/ddddddd after redirect
①rewrite {
regexp ^(.+)/$
to {1} {1}/ /index.php?{1}
}
②rewrite {
to {uri} /index.php?{uri}
}
③redir 301 {
if {uri} ends_with /
if {rewrite_uri} not_ends_with /
/ {rewrite_uri}
}
Double check whether you’re being redirected to xxx.com/index.php?/abc/ddddddd/ - I’ve got a feeling you’re actually getting redirected to xxx.com/index.php?/abc/ddddddd instead (note the lack of trailing slash).
Here’s why:
rewrite {
regexp ^(.+)/$
to {1} {1}/ /index.php?{1}
}
Notice how your regexp capture group excludes the trailing slash? You’re not putting the original URI back on the end, you’re putting it on sans trailing slash, and thus the redirect fires in the event of the fallback rewrite. Change it to:
rewrite {
regexp ^(.+)/$
to {1} {1}/ /index.php?{1}/
}
Perhaps my understanding of your desired behaviour was incorrect.
If you want to strip the trailing slash from the PHP index, and redirect the client, use: /index.php?{1}
If you don’t want to strip the trailing slash from the PHP index, and therefore not redirect the client, use: /index.php?{1}/ OR /index.php?{uri}
If you want to strip the trailing slash from the PHP index, but not redirect the client, use either form above on the rewrite, and add another condition to your redirect: if {rewrite_uri} not_starts_with /index.php?