PHP防抖(防重复提交)简单实现

PHP防抖(防重复提交)简单实现

本文编写时间:2023-06-05

需求

前端有时表单未做防抖处理,会给后端同时传递重复请求,希望后端代码能屏蔽。

实现:

这里给出本人的非常简单的实现。主要是针对简单需求的。复杂的需求代码肯定没这么简单。
前提:需安装redis。
欢迎各种讨论。

代码部分

仅供参考

异常类

/**
 * 防抖异常。这个类留空就行。
  */
class AntiRepeatException extends Exception
{
} 

//下面:框架的异常集中处理,自定义 的。这里是tp的。larave类似。


namespace app\common\exception;

use Exception;
use think\exception\Handle;

class MyException extends Handle
{
    public function render(Exception $e)
    {
        // 参数验证错误
        if ($e instanceof AntiRepeatException) {

            return json([ 'code'=>420, 'msg'=>$e->getMessage()  ])
        }
        // 其他错误交给系统处理
        return parent::render($e);
    }

}

下面是通用的防抖类。


namespace app\services\system;

use app\common\exception\AntiRepeatException;
use app\services\Redis;

/**
 * 通用.
 *
 *
 * @author
 */
class AntiRepeat
{

    /**
     * php 防抖通用方法。
     *
     * @param int $user_id 用户id,如设置成0,则表示后端对所有该控制器的请求,无差别限流。
     * @param int $cycle 周期,单位秒,一个周期内只允许一个请求。
     * @throws AntiRepeatException
     */
    public static function handle($user_id = 0, $cycle = 5)
    {
        //域名,注意,这几个参数应该使用各个框架自己提供的,这里是tp示例。
        $host = request()->host();

        //端口
        $port = request()->port();
        // 模块名
        $modules = request()->module();
        // 控制器名称
        $controller = request()->controller();
        // 方法名称
        $method = request()->action();

        $key = 'antiRepeat:' . $host . ':' . $port.":"  .$modules . ':' .
            $controller . ':' . $method . ':' . $user_id;

        $redis = Redis::getInstance();
        if ($redis->get($key) == '1') {
            throw  new AntiRepeatException('请不要提交重复请求');

        } else {
            $redis->setex($key, $cycle, 1);
        }
    }
}//end class

下面是使用示例


class TestController extends Controller
{
    // 假设该控制器的方法需要对登录用户限流 or 防抖。
    public function index444()
    {
        $user_id = Auth::id();// 得到当前登录用户。
        AntiRepeat::handle($user_id);
        // 下面做该接口正常的功能实现。
        // 。。。
        // 。。。
        return 'ok';
    }
}

总结

  • 这代码只能应付简单的需求,用于一些用户下订单之类的重要操作。
  • 限流是大概念,防抖可以看成某种简单的限流实现。
  • 即可针对单个登录用户,也可以对所有请求,但实际后者意义不大。
  • 后端独立实现,无需前端配合
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 6

Laravel 天然提供了一个 Cache::lock 的操作。

  1. 只使用一次的变量就不要声明了,可以直接写在行内
  2. 建议不要使用 get 的行为,直接使用 setNx
  3. 这个函数的入参设计的极其不合理,既然可能存在不限流的操作,自己不要实现锁就行了。锁的设计更应该是一个 提供 lock 方法的 trait,而不是一个固定的类。
  4. 错误消息错误码什么的完全可以丢进异常的 ctor 函数做。
    if ($e instanceof AntiRepeatException) {
       return json([ 'code'=>$e->getCode(), 'msg'=>$e->getMessage()])
    }
  5. 如果你想使用异常,是全部使用异常,如果你想使用 code 请全部使用 code。明显是个错误的操作却要给前端返回一个 HTTP Code 200 的响应。
1年前 评论
yyy123456 (楼主) 1年前

我自己做了一个功能,每次用户提交的POST数据都保存在sqlite数据库里面, 然后提交的时候,从sqlite的里面搜索,按用户ID,IP地址,和间隔时间来搜索判断,

优点是: 1、保存和记录了用户提交的所有记录,后台可备查,万一系统崩溃,数据也可恢复,而且这个也是可靠的原始数据,可以审计备查, 2、可以按时间参数来控制重复,比如24小时内禁止重复提交,或者3分钟内禁止提交 3、可以控制重复提交的次数,比如,可以24小时内重复提交3次,比如某些投票的应用,

1年前 评论
陈先生 1年前

假如很多方法都这样额外加一句 个人觉得不太灵活,用注解会不会好一点,或者一个基类属性来控制 $user_id = Auth::id();// 得到当前登录用户。 AntiRepeat::handle($user_id);

1年前 评论
yyy123456 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
58
粉丝
11
喜欢
63
收藏
104
排名:484
访问:1.8 万
私信
所有博文
社区赞助商