Laravel如何基于IP实现简易unique visitor counter功能

Laravel 基于IP识别的简易访客计数器实现方案
以下方案无额外第三方依赖,全部用Laravel原生能力实现,适合新手快速接入,核心逻辑为IP去重统计独立访客,计数规则可按需调整。
1. 创建数据存储表
首先建表存储访客IP记录,用于独立访客(UV)去重:
执行Artisan命令生成迁移文件:
php artisan make:migration create_visitor_counts_table
打开生成的database/migrations/xxxx_xx_xx_xxxxxx_create_visitor_counts_table.php文件,替换up方法内容为:
public function up() { Schema::create('visitor_counts', function (Blueprint $table) { $table->id(); $table->ipAddress('visitor_ip')->unique(); // 存储访客真实IP,唯一键防重复写入 $table->timestamp('last_visit_at'); $table->timestamps(); }); }
保存后执行迁移命令生成表:
php artisan migrate
再执行命令生成对应模型:
php artisan make:model VisitorCount
2. 编写全局计数中间件
用全局中间件实现全站访问自动计数,不需要在每个控制器重复写逻辑:
执行命令生成中间件:
php artisan make:middleware CountVisitor
打开app/Http/Middleware/CountVisitor.php,替换内容为:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use App\Models\VisitorCount; use Illuminate\Support\Facades\Cache; class CountVisitor { public function handle(Request $request, Closure $next) { // 跳过不需要计数的路径,比如后台、调试工具路由,可按需增减 if ($request->is('admin/*') || $request->is('telescope/*')) { return $next($request); } // 获取访客真实IP,兼容代理/CDN场景 $visitorIp = $request->getClientIp(); // 总浏览量(PV)每次访问都累加,用缓存存储减少数据库IO Cache::increment('site_total_pv'); // 优先查缓存判断IP是否已记录,减少数据库查询 $ipRecorded = Cache::remember('visitor_mark_'.$visitorIp, 60*24, function() use ($visitorIp) { // 默认同IP24小时内仅算1次独立访客,需要改时间阈值调整这里的碳方法参数即可 return VisitorCount::where('visitor_ip', $visitorIp) ->where('last_visit_at', '>=', now()->subDay()) ->exists(); }); if (!$ipRecorded) { // 新IP/超过24小时回访的IP,更新记录 VisitorCount::updateOrCreate( ['visitor_ip' => $visitorIp], ['last_visit_at' => now()] ); // 清除统计缓存,下次读取重新计算 Cache::forget('site_visitor_stats'); // 写入IP标记缓存,24小时内不再重复算UV Cache::put('visitor_mark_'.$visitorIp, true, 60*24); } return $next($request); } }
接下来注册中间件到全局Web组,打开app/Http/Kernel.php,找到$middlewareGroups下的web数组,在末尾追加一行:
\App\Http\Middleware\CountVisitor::class,
3. 全局共享统计数据
打开app/Providers/AppServiceProvider.php,在文件顶部引入对应门面,在boot方法中添加视图共享逻辑,所有Blade模板都可以直接调用统计数据:
use Illuminate\Support\Facades\Cache; use App\Models\VisitorCount; use Illuminate\Support\Facades\View; public function boot() { // 其他原有逻辑保持不变 View::share('visitorStats', Cache::remember('site_visitor_stats', 60*10, function() { return [ 'total_pv' => Cache::get('site_total_pv', 0), // 总访问次数 'total_uv' => VisitorCount::count() // 独立访客总数 ]; })); }
4. 前端渲染计数器
在需要显示计数器的Blade模板位置,添加以下代码,样式可自行调整匹配网站风格:
<div class="visitor-counter p-3 bg-gray-100 rounded inline-block"> <p class="m-0">总访问量:<strong class="text-red-500">{{ $visitorStats['total_pv'] }}</strong></p> <p class="m-0">独立访客:<strong class="text-blue-500">{{ $visitorStats['total_uv'] }}</strong></p> </div>
注意事项
- 如果网站使用CDN/反向代理,记得打开
config/trustedproxy.php配置信任的代理IP,否则会统计到CDN节点IP导致数据不准 - 小流量网站如果不想用缓存,可以把所有Cache相关逻辑去掉,直接查数据库读写,性能够用
- 如果需要调整同IP重复统计的时间间隔,修改中间件里
subDay()的参数即可,比如subHours(1)就是1小时内同IP仅算一次UV - 本地开发环境
127.0.0.1只会记录一次UV,部署到公网后会正常统计不同访客IP
内容的提问来源于stack exchange,提问作者Mahmoud Khosravi
相关产品推荐
相关产品推荐

