开启YII_DEBUG并检查assets权限、CSRF配置及自定义ErrorHandler的正确终止是解决Yii 500错误的关键:需设YII_DEBUG=true,确保web/assets可写,AJAX请求携带CSRF token,renderException末尾调用Yii::$app->end()。

500错误出现时先看 YII_DEBUG 是否开启
不打开调试模式,你永远看不到真实错误堆栈,只会卡在空白页或默认 500 提示。直接编辑 web/index.php,确认这行是 true:
defined('YII_DEBUG') or define('YII_DEBUG', true);
常见错误现象:改完仍没报错?检查是否被 Nginx/Apache 缓存了 500 响应,或 PHP 错误日志被关闭(display_errors = Off 或 log_errors = Off)。临时加一行 error_reporting(E_ALL); ini_set('display_errors', '1'); 到 index.php 开头更保险。
assets 目录不可写导致的 InvalidConfigException
这是生产环境最常触发 500 的原因之一,错误信息里一定含 The directory is not writable by the Web process 和 AssetManager.php。本质是 Yii 尝试生成前端资源(JS/CSS)但失败。
-
web/assets/目录权限必须对 Web 进程用户可写(不是 root,而是www-data、nginx或apache) - 别直接
chmod 777 web/assets—— 安全隐患大;应该用chown -R www-data:www-data web/assets(根据实际 Web 用户名调整) - 如果用了 Docker,注意挂载卷的 UID/GID 是否匹配容器内 Web 用户
- 某些部署会禁用
AssetManager::publish(),可改用asset/compress预发布,避免运行时写入
AJAX 请求因 CSRF 验证失败返回 500(实为 400,但被框架兜底成 500)
Yii 默认开启 CSRF 验证,原生 fetch 或 axios 发 POST 不带 token,会被 yii\web\ErrorHandler 捕获后转为 500 响应(尤其在非调试模式下),日志里实际是 BadRequestHttpException。
- 临时排查:在 Controller 中加
public $enableCsrfValidation = false;看是否恢复 —— 仅用于验证,勿留线上 - 正确做法:前端请求头带上
X-CSRF-Token,值从Yii::$app->request->getCsrfToken()获取,或从页面<meta name="csrf-token" content="...">读取 - API 场景建议关闭 CSRF(在
config/web.php的request组件中设'enableCsrfValidation' => false),改用 JWT 或 OAuth
自定义 ErrorHandler 后 redirect() 失效引发 500
重写 renderException() 时若未正确终止响应流程,后续代码(比如 redirect())可能继续执行,而此时 Response 已发送头部,再调 send() 就会报 500(PHP Warning: Cannot modify header information)。
- 在
renderException()结尾务必加Yii::$app->end();,而不是只echo或return - 不要在
renderException()里调$this->redirect()—— 它依赖完整应用生命周期,异常状态下不可靠 - 若需跳转,应在
catch块中处理,而非依赖renderException的输出逻辑
真正难排查的,往往是多个问题叠加:比如 assets 权限不对 + 关闭了 debug + 自定义 error handler 没 end(),结果只看到一个空 500,连日志都不写。先开 debug,再盯日志路径和权限,最后动代码逻辑。


















