FrequencyLimitation.php 1.9 KB
<?php
namespace app\api\behavior;

use think\Cache;

class FrequencyLimitation
{
    public function run(&$params)
    {
        // 行为逻辑
        $reqUri = trim(request()->path(), '/');
        $res = preg_match('/^(api\/cloudapi\/)/', $reqUri);
        if ($res){
            $statistics = preg_match('/^(api\/cloudapi\/statistics\/)/', $reqUri);
            if (!$statistics){//数据中心大屏统计页面接口不做限制
                if (!$this->requestAccess()){
                    echo json(['code'=>99999,'msg'=>'接口调用过于频繁','time'=>time(),'data'=>null])->send();die;
                }
            }
        }
    }

    /**
     * 访问频率限制
     * @param int $time 一样的参数每秒请求次数
     * @param int $limit 每分钟限制访问次数
     * @return bool
     */
    protected function requestAccess($time=1,$limit=20){
        //获取访问用户的IP
        $ip=md5(request()->ip());
        //获取访问的接口路径
        $path=request()->path();
        //将IP和访问的接口路径md5加密成一个字符串,这样子就代表同一个客户访问的接口。
        $UV=md5($ip.$path);
        //每个IP和接口每分钟不能超过的次数
        $cacheIp=Cache::get($UV)?:0;
        if($cacheIp){
            if($cacheIp>$limit){
                return false;
            }else{
                Cache::inc($UV,1);
            }
        }else{
            Cache::set($UV,1,60);
        }
        //将每个请求的IP地址、参数和路径拼接成同一个用户的一个完全相同的接口。
        $post=json_encode(request()->post());
        $name=md5($path.$post);
        //每个相同的数据多少时间内不能请求
        $cache=Cache::get($name);
        if($cache==$ip){
            return false;
        }else{
            Cache::set($name,$ip,$time);
            return true;
        }
    }
}