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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:09:19