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

Yii2: How to redirect to with UrlManager?

在我的 Yii2 配置中我有:

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

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

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

如果我去 site.com/search 就可以了。如果我转到 site.com/site/index 它也可以工作并显示相同的内容。如何重定向呼叫而不是仅显示 site/index 的响应?它还必须使用参数重定向 (site.com/site/index?param=1 -> site.com/search?param=1)

UrlManager 不重定向。它宁愿 rewrite like a web server. It is called routing.

如果您想在代码中进行重定向,可以使用 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 事件。您可以在配置数组中执行此操作:

选项 #1

[
    '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;
        }
    }
]

选项#2

或者如果您有 SearchController 使用:

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

选项 #3

第三个选项是配置网络服务器进行重定向。 这将是最快的解决方案

您可以使用UrlManager::$enableStrictParsing 来禁用路由匹配。如果您将其设置为 true,对 /site/index URL 的请求将不会匹配任何内容,应用程序将 return 404 错误。

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

但如果您确实想在其他情况下将路由用作 URL,则这可能不是一个选项。


您可能也对 UrlNormalizer class 感兴趣。这仍然是一个相对简单的组件并且(还)不支持您的用例,但实际上它是为此类任务而设计的。您可以考虑扩展它并为您的用例添加重定向逻辑 - 它应该比使用事件或专用操作和重定向规则更干净的解决方案。这可能也是一个很好的material PR 并将此功能推向核心框架。


惰性解决方案是创建重定向操作并添加规则以匹配需要重定向的 URL:

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);
    }
}

和规则:

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

我认为这会更普适和更普遍。在配置中:

'components' => [
],
'on beforeAction' => function ($event) {
    list($route, $params) = Yii::$app->urlManager->parseRequest(Yii::$app->request);
    $params = $_GET;

    if (is_string(Yii::$app->request->pathInfo)
        && strpos(Yii::$app->request->pathInfo, $route) === 0
    ) {
        if (strpos($route, '/') === false) {
            $route .= '/index';
        }

        $url = array_merge([0 => $route], $params);

        foreach(Yii::$app->urlManager->rules as $rule) {
            if ($rule->route === $route) {
                Yii::$app->response->redirect($url)->send();
                $event->handled = true;
            }
        }
    }
},

你可以简单地使用redirect,这更容易,它解决了你的问题,就像render一样。请参阅以下示例:

 return $this->redirect(['/site/index']);

P.S。路径可以是绝对路径或相对路径,您也可以使用别名或其他任何方式,例如:

// an alias of for home page
Yii::setAlias('@home', 'site/index');