资讯专栏INFORMATION COLUMN

H5活动抽奖

simon_chen / 674人阅读

摘要:在开放时间的基础上加上类型概率这种方式,也会出现多个用户相同奖品,但加上限制后,用户被分散在各个类型中,未中奖概率会比上面的例子低。

本文讲解内容

针对两类发奖需求的四种抽奖逻辑及细节

一般H5抽奖活动的发奖需求分为

1.一定中奖(奖品库存不空的情况下)
2.不一定中奖

发奖接口的最终实现要求

1.奖品不超发
2.唯一奖品单次发放
3.对并发有一定的限制

接口实战

1.根据奖品开放时间进行抽奖

public function award($openid)
    {
        $award = Award::find()->where(["openid" => ""])
            ->andWhere([">", "open_at", 0])->andWhere(["<", "open_at", time()])
            ->orderBy("open_at ASC")->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    "openid" => $openid
                ],
                "code = :code AND openid = :openid",
                [
                    ":code" => $award["code"],
                    ":openid" => ""
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

这种方式,多用户并发情况下,会出现多个用户相同奖品,由于update语句限制,拿到相同奖品码的用户中只有一人能中得奖品。

2.在开放时间的基础上加上类型概率

public function randAward($openid)
    {
        $number = rand(0, 100);
        $type = 5;
        if ($number < 10) {
            $type = 1;
        } else if ($number < 30) {
            $type = 2;
        } else if ($number < 70) {
            $type = 3;
        } else if ($number < 80) {
            $type = 4;
        }
        $award = Award::find()->where(["openid" => ""])
            ->andWhere([">", "open_at", 0])->andWhere(["<", "open_at", time()])
            ->andWhere(["type" => $type])
            ->orderBy("open_at ASC")->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    "openid" => $openid
                ],
                "code = :code AND openid = :openid",
                [
                    ":code" => $award["code"],
                    ":openid" => ""
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

这种方式,也会出现多个用户相同奖品,但加上type限制后,用户被分散在各个类型中,未中奖概率会比上面的例子低。

3.利用Redis奖品池的概念进行发奖

    public function redisAward($openid)
    {
        try {
            $redis = Yii::$app->redis->client();
            $code = $redis->LPop(self::AWARD_LIST_KEY);
        } catch (Exception $err) {
            return [];
        }
        $res = Award::updateAll(
            [
                "openid" => $openid
            ],
            "code = :code AND openid = :openid",
            [
                ":code" => $code,
                ":openid" => ""
            ]
        );
        if ($res) {
            $award = Award::find()->where(["code" => $code])->limit(1)->one();
            return ArrayHelper::toArray($award);
        }
        return [];
    }

这种利用预先生成奖品池的方式,奖品池不空的情况下,每个用户都会取走不同奖品码,要注意的是 前期生成奖品池及后期操作奖品池时,防止奖品码复用

4.根据奖品开放时间(类型)进行抽奖,换成用sql语句进行发奖

public function sqlAward($openid)
    {
        $sql = "UPDATE award SET openid = :openid 
                WHERE open_at > 0 AND openid = "" AND open_at < :time
                ORDER BY open_at ASC LIMIT 1";
        $res = Yii::$app->db->createCommand($sql, [":time" => time(), ":openid" => $openid])->execute();
        if ($res) {
            return Award::find()->where(["openid" => $openid])->limit(1)->asArray()->one();
        }
        return [];
    }

一定中奖需求下,建议采用Redis奖品池或者sql语句进行update
以上四种方式在多用户并发的情况下带来不一样的结果

除了多用户并发,还会出现恶刷情况,就是同一用户并发请求
这种情况应该在真正进入抽奖逻辑之前进行限制

可以根据实际需求搭配以下方式进行限制

public function actionAward()
    {
        $openid = "okjkLj7-UL4gXknY9bDkFn0O6Jos";
        $redis = Yii::$app->redis->client();
//            用户单次数
        if (!$redis->sAdd(self::USER_LIST_KEY, $openid)) {
            return [];
        }
        return $this->sqlAward($openid);
    }

也可以限制抽奖人数

public function actionAward()
    {
        $openid = CommonTool::randString(32);
        try {
            $redis = Yii::$app->redis->client();
//            抽奖用户数量
            $list = $redis->sMembers(self::USER_LIST_KEY);
            if (count($list) > 1000) {
                return ;
            }
        } catch (Exception $err) {

        }
        $award = $this->sqlAward($openid);
    }
写在最后的最后

H5活动抽奖接口需要注意几点
1.检查用户有效性
2.限制单用户访问次数
3.使用概率让用户分流,从而控制真正进入抽奖逻辑的请求
4.记录抽奖领奖等相关操作的时间设备IP等..
5.控制奖品的分布(时间,插空,概率等)
6.做好索引关系

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30763.html

相关文章

  • 移动端 h5开发相关内容总结(三)

    摘要:就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。标签的属性应当与相关元素的属性相同。所以在和移动我分别用了两种方案,传统布局实现,弹性盒实现。前者是控制弹性盒的内容垂直方向居中,后者控制内容水平方向居中。 之前写过两篇开发中遇到的问题和解决方案。当时是CSS 和 JavaScript 分开写的。现在写这篇文章的时候感觉很多内容都是有内在联系的,所以不好分开。...

    cnTomato 评论0 收藏0
  • 移动端 h5开发相关内容总结(三)

    摘要:就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。标签的属性应当与相关元素的属性相同。所以在和移动我分别用了两种方案,传统布局实现,弹性盒实现。前者是控制弹性盒的内容垂直方向居中,后者控制内容水平方向居中。 之前写过两篇开发中遇到的问题和解决方案。当时是CSS 和 JavaScript 分开写的。现在写这篇文章的时候感觉很多内容都是有内在联系的,所以不好分开。...

    antyiwei 评论0 收藏0
  • 移动端 h5开发相关内容总结(三)

    摘要:就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。标签的属性应当与相关元素的属性相同。所以在和移动我分别用了两种方案,传统布局实现,弹性盒实现。前者是控制弹性盒的内容垂直方向居中,后者控制内容水平方向居中。 之前写过两篇开发中遇到的问题和解决方案。当时是CSS 和 JavaScript 分开写的。现在写这篇文章的时候感觉很多内容都是有内在联系的,所以不好分开。...

    MonoLog 评论0 收藏0
  • jQuery带次数带弹窗的大转盘抽奖代码(支持h5

    摘要:您已拥有次抽奖机会,点击立刻抽奖开始抽奖初始次数,由后台传入为随机出来的结果,根据概率后的结果如果在执行就退出标志为在执行先判断是否登录未登录则执行下面的函数请先登录登录了就执行下面当抽奖次数为的时候执行没有次数了还有次 showImg(https://segmentfault.com/img/bVbqAdu); showImg(https://segmentfault.com/img...

    lemon 评论0 收藏0

发表评论

0条评论

simon_chen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<