You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2 v2模块已加载但所有路由均返回404错误求助

Yii2 V2模块所有端点返回404问题排查与解决

问题背景

项目中新增V2模块(复制V1模块修改而来,V1运行正常),已替换所有V1相关内容并检查大小写正确性。模块在web.php中注册成功,日志显示"ApiV2Module is bootstrapping"且V2模块已加载,但使用Postman测试所有V2端点(如<url>/v2/user/get-level-exp/63)均返回404错误。


相关配置与代码

1. web.php模块注册配置

'bootstrap' => [ 'log', 'v1', 'v2'],
'modules' => [
        'v1' => [
            'class' => api\modules\v1\ApiV1Module::class,
            'controllerNamespace' => 'api\modules\v1\controllers',
        ],
        'v2' => [
            'class' => api\modules\v2\ApiV2Module::class,
            'controllerNamespace' => 'api\modules\v2\controllers',
        ],
],

2. web.php URL管理器配置

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
    ],
],

3. ApiV2Module.php路由规则

public function bootstrap($app)
{
    
    \Yii::info("ApiV2Module is bootstrapping", __METHOD__);
    
    \Yii::info("Incoming request to: " . \Yii::$app->request->url, __METHOD__);
    
    $app->getUrlManager()->addRules([
        '/v2/user/<id:\d+>' => '/v2/user/index',
        '/v2/friends/<id:\d+>' => '/v2/friends/index',
        '/v2/challenge/<id:\d+>' => '/v2/challenge/index',
        '/v2/challenge/<id:\d+>/<action>' => '/v2/challenge/<action>',
        '/v2/exercises/<id:\d+>' => '/v2/exercises/index',
        '/v2/exercises/<id:\d+>/<action>' => '/v2/exercises/<action>',
        '/v2/notifications/<page:\d+>' => '/v2/notifications/index',
        '/v2/notifications/<_a>' => '/v2/notifications/<_a>',
        '/v2/user/goals/<id:\d+>' => '/v2/user/goals',
        '/v2/user/exp/<id:\d+>' => '/v2/user/exp',
    ]);
}

4. UserController核心代码

<?php namespace api\modules\v2\controllers;

use api\components\Controller;
use api\modules\v2\models\User\UserInfoModel;
use api\modules\v2\models\User\UserUpdateModel;
use api\modules\v2\models\User\UserDeleteModel;
use api\modules\v2\actions\User\DashboardAction;

use api\modules\v2\models\UserGoalsModel;
use api\modules\v2\models\UserLevelExpModel;

class UserController extends Controller
{
    public function actionIndex($id = null)
    {
        \Yii::info("Entering actionIndexV2 with ID: $id", __METHOD__);
        if ($this->request->isGet) {
            return $this->processActionModel(
                new UserInfoModel([
                    'user_id' => $id,
                    'logged_user_id' => \Yii::$app->user->id,
                ]),
            );

        } else if ($this->request->isPatch) {
            return $this->processActionModel(
                new UserUpdateModel([ 'user_id' => \Yii::$app->user->id ]),
            );
        } else if ($this->request->isDelete) {
            return $this->processActionModel(
                new UserDeleteModel([ 'user_id' => $id ]),
            );
        }
    }

    public function actions()
    {
        \Yii::info("Actions method called in UserController V2", __METHOD__);
        return [
            'dashboard' => DashboardAction::class,
        ];
    }
    
    // 获取并更新目标
    public function actionGoals($id)
    {
        \Yii::info("Entering actionGetGoals with ID: $id", __METHOD__);
        $model = new UserGoalsModel(['user_id' => $id]);
        return $this->processActionModel($model);
    }

    public function actionUpdateGoals($id)
    {
        \Yii::info("Entering actionUpdateGoals with ID: $id", __METHOD__);
        $model = new UserGoalsModel(['user_id' => $id]);
        $newGoals = \Yii::$app->request->post('goals');
        return $model->updateGoals($newGoals);
    }

    // 获取并更新等级与经验
    public function actionExp($id)
    {
        \Yii::info("Entering actionGetLevelExp with ID: $id", __METHOD__);
        $model = new UserLevelExpModel(['user_id' => $id]);
        return $this->processActionModel($model);
    }

    public function actionUpdateLevelExp($id)
    {
        \Yii::info("Entering actionUpdateLevelExp with ID: $id", __METHOD__);
        $model = new UserLevelExpModel(['user_id' => $id]);
        $newLevel = \Yii::$app->request->post('level');
        $newExp = \Yii::$app->request->post('exp');
        return $model->updateLevelExp($newLevel, $newExp);
    }
}

5. UserLevelExpModel代码

<?php

namespace api\modules\v2\models\User;

use yii\base\Model;
use app\models\User;
use yii\web\NotFoundHttpException;

class UserLevelExpModel extends Model
{
    public int $user_id;

    public function process(): mixed
    {
        $user = User::findOne($this->user_id);
        if (!$user) {
            throw new NotFoundHttpException("User not found");
        }

        return [
            'level' => $user->level,
            'exp' => $user->exp,
        ];
    }

    public function updateLevelExp($newLevel, $newExp): bool
    {
        $user = User::findOne($this->user_id);
        if (!$user) {
            throw new NotFoundHttpException("User not found");
        }

        $user->level = $newLevel;
        $user->exp = $newExp;
        return $user->save();
    }
}

排查与解决方案

1. 路由规则缺失

测试的/v2/user/get-level-exp/63没有对应的路由规则,当前V2模块仅配置了/v2/user/exp/<id:\d+>对应actionExp,但未添加get-level-exp的映射规则。

  • 修复方案:在ApiV2Module的bootstrap方法中新增路由规则:
    '/v2/user/get-level-exp/<id:\d+>' => '/v2/user/exp',
    
    或直接使用默认路由匹配的端点/v2/user/exp/63(对应actionExp方法)。

2. 路由规则前缀异常

当前路由规则中路径前带了/,可能导致匹配失败,Yii的URL规则不需要开头的/,去掉后匹配更可靠。

  • 修复方案:修改所有路由规则,去掉开头的/,例如:
    'v2/user/<id:\d+>' => 'v2/user/index',
    'v2/user/exp/<id:\d+>' => 'v2/user/exp',
    // 其他规则同理调整
    

3. 启用默认路由匹配

如果自定义路由覆盖不全,可在urlManager的rules中添加默认路由规则,确保未匹配到自定义规则的请求能正常解析:

'<module:\w+>/<controller:\w+>/<action:\w+>/<id:\d+>' => '<module>/<controller>/<action>',

4. 验证文件与命名空间一致性

确认api\modules\v2\ApiV2Module类文件存在,且命名空间与文件路径一致;控制器文件需放在api/modules/v2/controllers/目录下,命名空间正确。

5. 开启路由调试日志

在web.php中添加路由调试日志配置,查看请求的路由匹配过程:

'log' => [
    'targets' => [
        [
            'class' => 'yii\log\FileTarget',
            'levels' => ['info', 'trace'],
            'categories' => ['yii\web\UrlManager*'],
        ],
    ],
],

通过日志可明确请求是否命中正确的路由规则,定位匹配失败原因。

内容的提问来源于stack exchange,提问作者Julian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:59:50