Yii2:如何使用UrlManager重定向到?

In my Yii2 config I have:

'components' => [
    'urlManager' => [

        'baseUrl'         => '',
        'enablePrettyUrl' => true,
        'showScriptName'  => false,

        'rules' => [
            'search' => 'site/index',
            ...
        ],
    ...

If I go to site.com/search it works. If I go to site.com/site/index it also works and shows the same content. How to redirect the call instead of just showing the response of site/index? It must also redirect with params (site.com/site/index?param=1 -> site.com/search?param=1)

The UrlManager does not redirect. It rather does a rewrite like a web server. It is called routing.

If you would like to do a redirect in your code you can use Response::redirect(). If you don't have a SearchController where you can put this statement in an action, you can place it into the beforeAction event event. You can do this in your configuration array:

[
    'components' = [
        ...
    ],
    'on beforeAction' => function ($event) {
        if(Yii::$app->request->pathInfo === 'search') {
            $url = 'site/index?' . Yii::$app->request->queryString;
            Yii::$app->response->redirect($url)->send();
            $event->handled = true;
        }
    }
]

Or if you have SearchController use:

class SearchController extends \yii\web\Controller {
    public function actionIndex() {
        $url = 'site/index?' . Yii::$app->request->queryString;
        return $this->redirect($url);
    }
}

Third option is to configure the web server to do the redirect. That would be the fastest solution.

You may use UrlManager::$enableStrictParsing to disable matching by route. If you set it to true, request to /site/index URL will not match anything and app will return 404 error.

'components' => [
    'urlManager' => [
        'baseUrl' => '',
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'enableStrictParsing' => true,
        'rules' => [
            'search' => 'site/index',
            // ...
        ],
    // ...

But this may be not an option if you actually want to use routes as URLs in other cases.


You may also be interested in the UrlNormalizer class. This is still a relatively simple component and does not (yet) support your use case, but in fact it was designed for such tasks. You may consider extending it and add redirection logic for your use case - it should be much more clean solution than using events or dedicated actions and rules for redirections. It may be also a good material for PR and pushing this feature to core framework.


Lazy solution would be to create redirection action and add rules to match URLs that needs to be redirect:

class RedirectController extends Controller {

    public function actionRedirect($action, $controller, $module = null) {
        if ($action === $this->action->id && $controller === $this->id && $module === null) {
            // prevent to access action directly and redirection loops
            throw new NotFoundHttpException();
        }

        $url = Yii::$app->request->get();
        unset($url['action'], $url['controller'], $url['module']);
        array_unshift($url, '/' . ltrim(implode('/', [$module, $controller, $action]), '/'));

        return $this->redirect($url);
    }
}

And rules:

'urlManager' => [
    // ...
    'rules' => [
        'search' => 'site/index',
        [
            'pattern' => '<controller:(site)>/<action:(index)>',
            'route' => 'redirect/redirect',
            'model' => UrlRule::PARSING_ONLY,
        ],
        // ...
    ],
],