Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UrlRule Problem with trailing slash (/) #7670

Closed
Bhoft opened this issue Mar 11, 2015 · 23 comments · Fixed by #12240
Closed

UrlRule Problem with trailing slash (/) #7670

Bhoft opened this issue Mar 11, 2015 · 23 comments · Fixed by #12240
Assignees
Labels
Milestone

Comments

@Bhoft
Copy link
Contributor

Bhoft commented Mar 11, 2015

Hi i have added a UrlManager rules like given below added to my config

  '<project:[-a-zA-Z]+>/<controller:\w+>' => '<controller>',
  '<project:[-a-zA-Z]+>/<controller:\w+>/<action:\w+>' => '<controller>/<action>',

If i then call a url like

/projectname/controllername/action            (works)
/projectname/controllername           (works pointing to the default action in the controller)

/projectname/controllername/              (with trailing slash doens't work)

But the Url with a trailing slash produces a 404 error on the SiteController.

This is because the UrlRule doesn't match.
if i change the UrlRule to the code below (\w* instead of \w+) the default controller action is called.

  '<project:[-a-zA-Z]+>/<controller:\w+>/<action:\w*>' => '<controller>/<action>',

I also tested the UrlRules in yii1 but there the UrlRules from the top are also working with a trailing / in the Url but not in yii2.

So I guess there is some kind of "bug".
I Don't Know if the trailing slashes are removed in the Request in yii1 but not in yii2.
But there is clearly some difference between the 2 frameworks.

Regards Horizons

@samdark
Copy link
Member

samdark commented Mar 11, 2015

Yes, there's difference and it's intentional.

@samdark
Copy link
Member

samdark commented Mar 11, 2015

@yiisoft/core-developers it's not the first time people are asking about it. Maybe we should redirect to proper URL instead of not allowing to use incorrect one altogether?

@qiangxue qiangxue added this to the 2.1.x milestone Mar 11, 2015
@Bhoft
Copy link
Contributor Author

Bhoft commented Mar 18, 2015

is it somehow possible that something is added to the pattern so that a optional trailing / is in the pattern.
In my project case where the url was only /projectname or /projectname/ it would be something like

$this->pattern ='#^(?P<project>[-a-zA-Z]+)(?:[/])?$#u';
instead of 
$this->pattern ='#^(?P<project>[-a-zA-Z]+)$#u';

so this was added (?:[/])?

So that both url's would work.
Maybe this trailing slash pattern is added to the pattern in the UrlRule init when some placeholder is in the pattern or some variable is set.

@klimov-paul
Copy link
Member

#1807

@nkovacs
Copy link
Contributor

nkovacs commented May 12, 2015

The documentation is wrong. It says "the leading and ending slashes are ignored": http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html#url-rules

@samdark
Copy link
Member

samdark commented Jun 15, 2015

It seems to a bigger problem than I've thought. Wordpress is adding / at the end of all links posted.

@samdark samdark modified the milestones: 2.0.5, 2.1.x Jun 15, 2015
@samdark
Copy link
Member

samdark commented Jun 15, 2015

While it could be solved serverside, it's better to do in Yii itself else there will be lots and lots of unexpected 404s.

@samdark
Copy link
Member

samdark commented Jul 8, 2015

Could be done app-side like the following:

$config = [
    // ...
    'params' => require(__DIR__ . '/params.php'),

    // redirect to the page with the trailing slash
    'on beforeRequest' => function () {
        $app = Yii::$app;
        $pathInfo = $app->request->pathInfo;
        if (!empty($pathInfo) && substr($pathInfo, -1) !== '/') {
            $app->response->redirect('/' . rtrim($pathInfo) . '/', 301);
        }
    },
];

@mrsombre
Copy link

This leads to problems with search engines, as URI with and without ending slash may be different documents. All site should use only one style and return 301 or 404 for wrong ones.

@samdark
Copy link
Member

samdark commented Jul 23, 2015

301 is better.

@mrsombre
Copy link

@samdark then it should be an option to choose between with/without ending slash. And option to allow both for people who don't care about seo. And maybe 404 as default option (for BC)?

@samdark
Copy link
Member

samdark commented Jul 24, 2015

  • There's no problem with serving 301 instead of 404.
  • To choose with or without / one could configure UrlManager even now.
  • "Don't care" would not make sense if there will be 301 i.e. people would be redirected no matter which URL is used.

@pabloneruda1
Copy link

This redirect rule works for me in htaccess:

RewriteCond %{THE_REQUEST} \s/+(.+?)/+[?\s]
RewriteRule /$ /%1 [R,L]

@gerpayt
Copy link

gerpayt commented Sep 23, 2015

Add a route at last line '<url:.+>/' => 'site/redirect',

and add a action

public function actionRedirect($url = '')
{
    if (substr($url, -1) == '/') {
        return $this->redirect('/' . substr($url, 0, -1));
    } else {
        throw new NotFoundHttpException;
    }
}

@samdark samdark self-assigned this Sep 23, 2015
@pabloneruda1
Copy link

right, thanks gerpayt

@sganz
Copy link

sganz commented Oct 27, 2015

Not sure where all the slash/no slash ended up but ran into something as well when porting some Yii1 code over to Yii2.

Docs have it stated incorrectly if the a requests getPathInfo() is used.

In the docs it states -

A path info refers to the part that is after the entry script and before the question mark (query string). The starting and ending slashes are both removed.

When doing something like $request->getPathInfo(); it returns the trailing slash. This is not so much about handling the route, but different results expected for getPathInfo().

No big deal either way, just want the docs to match what it really is supposed to be, solved by rtrim() the slash prior to using the getPathInfo() value in my code, again not a huge one, just letting folks know the docs may not match functionality.

Thanks

Sandy

@SilverFire
Copy link
Member

@sauron918 please create a separated issue for your problem

dynasource added a commit to dynasource/yii2 that referenced this issue Feb 2, 2016
- resolve Url like in the original code
- if request can not be resolved, try again with suffix (if any)
- if request is then resolved, then redirect to the corresponding url

To be able to do this repetition, a new function is created called 'resolveRequest'.
This function looks like the old 'resolve' function.
The old revolve function is use to act as a controller, including a redirect
@schojniak
Copy link
Contributor

@gerpayt:

slash should be inside regular expression:
'<url:.+/>' => 'site/redirect'

some improvements: 301 redirect, baseUrl, one redirect in case of many slashes

public function actionRedirect($url)
{
    if (substr($url, -1) == '/') {
        return $this->redirect(Yii::$app->getRequest()->getBaseUrl() . '/' . rtrim($url, '/'), 301);
    } else {
        throw new NotFoundHttpException;
    }
}

@cronfy
Copy link
Contributor

cronfy commented Apr 18, 2016

@samdark could you please take a look at my pull request? I hope it will help to solve the issue. I use this approach on sites I develop.

@jnanendraveer
Copy link

Still waiting for write answer. Why I will use 301 redirect for trailing slash?. As you guys know in yii1 better for url manager. Some guys has post like that
/projectname => projectcontroller/index
/projectname/ => projectcontroller/index
/projectname/action => projectcontroller/action

/projectname/projectspecifc_controller => projectspecifc_controller/index
/projectname/projectspecifc_controller/ => projectspecifc_controller/index
/projectname/projectspecifc_controller/action => projectspecifc_controller/action

It's not perfect answer. I have configure like that
'baseUrl' => '/',
'enablePrettyUrl' => true,
'showScriptName' => false,
'suffix' => '/',
'enableStrictParsing' => true,

My code working fine.

Thanks

@samdark
Copy link
Member

samdark commented Aug 30, 2016

Because search engines think a/ and a are different URLs and since these contain the same content, your website is getting penalized for duplicated content. 301 solves the issue.

samdark added a commit that referenced this issue Aug 30, 2016
@agungsijawir
Copy link

Another .htaccess rewrite rule before checking directory.

    # see http://stackoverflow.com/a/11880879/2485734
    RewriteCond %{REQUEST_URI} !(/$|\.)
    RewriteRule (.*) %{REQUEST_URI}/ [R=301,L]

and the config for UrlManager, enabling suffix

return [
    'class' => 'yii\web\UrlManager',
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'suffix' => '/',
    'rules' => [
        '/' => 'site/index',
        'product/<slug>' => 'product/view',
        'product-category/<name>' => 'product-category/index',
        'search/<keyword>' => 'search/result',
    ],
];

@rishad2m8
Copy link

I've experienced similar issue with IIS. So if anyone still experiencing trailing slash issue,

Please use following URL rewrite Rule in web.config

<rule name="SEO - Remove trailing slash" stopProcessing="false">
                    <match url="(.*)/$" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    </conditions>
                    <action type="Redirect" url="{R:1}" />
                </rule>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment