Laravel维护页默认渲染逻辑在CheckForMaintenanceMode中间件触发后由Handler::render()处理MaintenanceModeException,返回硬编码HTML;自定义需在app/Exceptions/Handler.php中捕获该异常并用response()->view()渲染Blade模板。
Laravel 的维护模式页面由 Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode 中间件触发,但实际渲染交给了 render 钩子——它本质是 App\Exceptions\Handler 类中 render() 方法对 MaintenanceModeException 的响应处理。
关键点:Laravel 不会自动加载视图模板,而是直接返回一个硬编码的 HTML 响应(503 状态 + 内联样式),除非你显式拦截这个异常。
resources/views,所以改 resources/views/errors/503.blade.php 没用php artisan down 生成的 storage/framework/down 文件只是开关,不参与渲染app/Exceptions/Handler.php 的 render() 方法里处理 MaintenanceModeException
在 app/Exceptions/Handler.php 的 render() 方法开头添加判断,捕获 MaintenanceModeException 并返回自定义响应:
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\MaintenanceModeException;
// ...
public function render($request, Throwable $exception)
{
if ($exception instanceof MaintenanceModeException) {
return response()->view('maintenance', [], 503)
->header('Retry-After', 300);
}
return parent::render($request, $exception);
}
注意:response()->view() 是关键,它让 Laravel 渲染你自己的 Blade 模板(如 resources/views/maintenance.blade.php);Retry-After 头部可选,但符合 HTTP 503 规范。
parent::render(),否则仍会走默认逻辑php artisan view:clear
常见失效场景不是代码写错,而是异常根本没走到 Handler::render() —— 因为 MaintenanceModeException 在中间件链早期就被捕获并响应了。
根本原因:Laravel 9+ 默认启用了「预加载维护检查」,即在内核启动阶段就抛出异常,绕过整个 HTTP 栈。此时 Handler::render() 完全不执行。
render() 里加 dd('here'),执行 php artisan down 后访问页面,如果没触发,说明被提前拦截config/app.php 中设置 'maintenance' => 'cookie'(Laravel 10.27+ 支持)或降级到传统中间件模式Illuminate\Foundation\Http\Middleware\CheckFo
rMaintenanceMode 的 handle() 方法,或在 bootstrap/app.php 顶部手动注册自定义中间件替代原生逻辑维护页通常需要显示倒计时、预计恢复时间或客服联系方式,但此时应用服务(如数据库、Redis、队列)大概率已不可用。不能依赖 config() 或 env() 动态读取。
推荐做法是把变量固化进模板或通过命令参数注入:
php artisan down --message="系统升级中" --retry=600
然后在 app/Exceptions/Handler.php 中提取:
if ($exception instanceof MaintenanceModeException) {
$message = $exception->getMessage() ?: '系统正在维护';
$retry = $exception->getRetryAfter() ?: 300;
return response()->view('maintenance', [
'message' => $message,
'retry_after' => $retry,
], 503);
}
$exception->getMessage() 可拿到 php artisan down --message 的值$exception->getRetryAfter() 对应 --retry 参数(单位秒)DB::table() 或 Cache::get(),这些会直接报错或超时最易忽略的一点:维护页面的 CSS/JS 必须是内联或 CDN 托管,不能依赖 mix() 或 @vite 生成的哈希文件——构建产物可能未更新,或本地开发服务器已停。