本文目录导读:

- 使用预定义 IP 白名单(最简单)
- 使用中间件方式(推荐)
- 使用 Laravel 的
php artisan down命令 - 在
.env文件中配置 - 创建维护模式视图
- 高级方案:使用 Redis 动态管理 IP
- 推荐使用方案
在 Laravel 中设置维护模式并排除特定 IP,有多种方法,以下是详细的解决方案:
使用预定义 IP 白名单(最简单)
在 bootstrap/app.php 中配置:
<?php
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 配置维护模式排除的 IP
$app->configure('app');
return $app->createApplication(function ($app) {
// 在维护模式下允许访问的 IP 列表
$app->make(Illuminate\Contracts\Http\Kernel::class)
->setMaintenanceModeHandler(function () {
// 定义允许访问的 IP
$allowedIPs = [
'127.0.0.1', // 本地
'192.168.1.100', // 办公室 IP
'103.21.58.61', // 特定 IP
];
$currentIP = request()->ip();
if (in_array($currentIP, $allowedIPs)) {
return response()->make('', 200);
}
// 返回维护模式页面
return response()->make(
view('errors.maintenance'),
503,
['Retry-After' => 3600]
);
});
});
使用中间件方式(推荐)
创建自定义维护模式中间件
php artisan make:middleware CheckMaintenanceMode
中间件代码
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckMaintenanceMode extends Middleware
{
/**
* 允许访问的 IP 地址列表
*/
protected $allowedIPs = [
'127.0.0.1',
'192.168.1.0/24', // 支持 CIDR 格式
'103.21.58.61',
];
/**
* 处理请求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// 如果应用处于维护模式且当前 IP 不在白名单中
if ($this->app->isDownForMaintenance() &&
!$this->isAllowedIP($request->ip())) {
return response()->json([
'message' => '系统正在维护中,请稍后再试',
'code' => 503
], 503);
}
return $next($request);
}
/**
* 检查 IP 是否在允许列表中
*/
protected function isAllowedIP($ip)
{
foreach ($this->allowedIPs as $allowedIP) {
if ($this->ipMatches($ip, $allowedIP)) {
return true;
}
}
return false;
}
/**
* 检查 IP 匹配(支持通配符和 CIDR)
*/
protected function ipMatches($ip, $allowedIP)
{
// 完全匹配
if ($ip === $allowedIP) {
return true;
}
// 支持 * 通配符,如 192.168.*.*
if (strpos($allowedIP, '*') !== false) {
$pattern = str_replace('*', '(.*)', preg_quote($allowedIP, '/'));
return (bool) preg_match("/^{$pattern}$/", $ip);
}
// 支持 CIDR 格式,如 192.168.1.0/24
if (strpos($allowedIP, '/') !== false) {
return $this->ipInCidr($ip, $allowedIP);
}
return false;
}
/**
* 检查 IP 是否在 CIDR 范围内
*/
protected function ipInCidr($ip, $cidr)
{
list($subnet, $bits) = explode('/', $cidr);
if ($bits == 0) {
$bits = 32;
}
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask;
return ($ip & $mask) == $subnet;
}
}
注册中间件
在 app/Http/Kernel.php 中注册:
protected $middleware = [
// ...
\App\Http\Middleware\CheckMaintenanceMode::class,
];
使用 Laravel 的 php artisan down 命令
# 启用维护模式,排除特定 IP php artisan down --allow=127.0.0.1 --allow=192.168.1.0/24 # 或者使用配置文件 php artisan down --allow=103.21.58.61
查看当前维护模式状态
php artisan down --status
在 .env 文件中配置
在 .env 文件中添加:
MAINTENANCE_ALLOWED_IPS=127.0.0.1,192.168.1.100,103.21.58.61
然后在代码中使用:
$allowedIPs = explode(',', env('MAINTENANCE_ALLOWED_IPS', ''));
protected function setUpMaintenanceMode()
{
if ($this->app->isDownForMaintenance()) {
$allowedIPs = explode(',', env('MAINTENANCE_ALLOWED_IPS', ''));
if (!in_array(request()->ip(), $allowedIPs)) {
abort(503, '系统维护中');
}
}
}
创建维护模式视图
创建 resources/views/errors/maintenance.blade.php:
<!DOCTYPE html>
<html>
<head>系统维护中</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 50px;
background: #f5f5f5;
}
.maintenance-box {
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
max-width: 600px;
margin: 100px auto;
}
h1 {
color: #333;
margin-bottom: 20px;
}
p {
color: #666;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="maintenance-box">
<h1>🔧 系统维护中</h1>
<p>系统正在进行维护升级,预计将在 <strong>30分钟</strong> 内完成。</p>
<p>给您带来的不便,敬请谅解!</p>
</div>
</body>
</html>
高级方案:使用 Redis 动态管理 IP
<?php
namespace App\Services;
use Illuminate\Support\Facades\Redis;
class MaintenanceModeManager
{
protected $redis;
public function __construct()
{
$this->redis = Redis::connection();
}
public function addAllowedIP($ip)
{
$this->redis->sadd('maintenance:allowed_ips', $ip);
}
public function removeAllowedIP($ip)
{
$this->redis->srem('maintenance:allowed_ips', $ip);
}
public function isAllowed($ip)
{
return $this->redis->sismember('maintenance:allowed_ips', $ip);
}
public function getAllowedIPs()
{
return $this->redis->smembers('maintenance:allowed_ips');
}
}
推荐使用方案
对于大多数项目,推荐使用方案 2(中间件方式),因为:
- 代码清晰,易于维护
- 支持复杂的 IP 匹配逻辑(通配符、CIDR)
- 可以自定义响应格式
- 方便切换功能
记得在生产环境测试时,确保你当前的 IP 在白名单中,否则可能会被锁在外面!