自己做一个抽奖盲盒小程序-人人都是 Serverless 架构师 | “盲盒抽奖”创意营销活动实践
导读:当 Serverless 与低代码两种不同的技术在同一个业务中交叉,会呈现出什么样的价值?本文以 Serverless Devs 做的一个创意营销活动“盲盒抽奖”为例,给大家讲解如何将 Serverless 与低代码结合起来,去满足一个业务需求。
作者 | 韩邪 & 姜瑜
当 Serverless 与低代码两种不同的技术在同一个业务中交叉,会呈现出什么样的价值呢?本文以 Serverless Devs 做的一个创意营销活动“盲盒抽奖”为例,给大家讲解如何将 Serverless 与低代码结合起来,去满足一个业务需求。
前言
线上H5创意动画结合线下实物奖励是互联网营销活动的常用手段,为了抓住关键时间节点,活动从策划到实施的周期一般较短,如何在短时间内实现线上服务对技术开发人员来说是一个不小的挑战。
尤其当需求增多,比如增加后端管理、关键前端接入数据点时,挑战往往加倍。对于开发者来说,除了完成核心业务需求外,往往还需要关注非业务需求之外的其他情况,比如系统访问安全、高并发流量响应、可观察的系统运行指标等。
过去这样的需求往往需要产品、前端、后端、设计、测试、运维等多个角色的参与,投入产出比比较低,活动的可持续性也比较差。而今天利用 Serverless+低代码技术,我们可以大大降低这类活动的成本,并将其转化为持续性活动,从而大大提升运营效果。
事实上,Serverless Devs 在本次盲盒抽奖活动中仅投入了 3.5 个人,就完成了活动策划、产品设计、前后端实现、系统部署和运维。并且借助 Serverless 服务能力,轻松应对了系统访问安全、高并发流量、系统可观测性等非业务挑战。功能的完备+效率的提升让本次运营收益颇丰,而活动服务的模板沉淀也为后续的同类活动打下了良好的基础。
“盲盒抽奖”活动整体流程如下:
需求设计(包括业务逻辑、交互逻辑) 设计稿 低代码实现 前端编码 实现 Serverless 服务联调 测试部署 线上活动 问题修复 活动后回顾
应用效果预览:
“1分钟Serverless快速部署盲盒”抽奖活动已经结束,不过感兴趣的同学还可以体验一下:
/adc/系列/…
架构预览:
这种部署架构没有采用阿里云 API 网关,而是直接采用函数计算自定义运行时作为托管形式。这样做是因为这个需求的特殊性。我们是**“自己部署,自己画图”**,其实就是端侧接入是去中心化的,端侧接入服务也比较薄,只是数据处理接口调用和静态渲染服务。之后再由一个集中的逻辑后台处理中奖概率,管理奖品查询数据库。
如果你自己做集中式活动后台,建议可以参考下面的架构模型,使用API网关作为流量入口,这样可以有更多的安全限制,扩展也更加灵活。
实现分析
低代码实现前端交互
本次前端实现用的是低代码量主力hype4,hype4的具体使用这里就不详细介绍了,有兴趣的同学可以自行搜索。
设计稿除了裁剪出需要的图片之外,还要按照Flash的方式实现动画效果,最后添加js代码实现界面访问,场景切换等,整个过程比全程编码要快很多,特别是在动画效果实现方面,比纯手写的效率提高了2-3倍。
数据层无服务器服务
如架构图所示,这里的数据层其实就是我们理解的SSF,这一层只起到数据的转发和静态渲染的作用。代码实现比较简单,使用express框架然后以函数计算自定义运行时的形式部署。
目的是让这个服务既能承载静态内容,又能承载动态数据转发,值得注意的是,用户信息的获取也是在这一层实现的。
这里获取的是阿里云用户的accountId,方便对齐中奖信息进行奖品发放,对于普通开发者来说,这个参数意义不大。
我们会提前部署好抽奖后端,接下来每个用户都会部署这一层服务,访问部署好的服务,然后把uid等基本信息传给抽奖后端,发起抽奖,最后把中奖结果透传到前端展示,作为管理员,你可以通过后端操作来设置奖品和中奖概率。
后台抽奖逻辑实现
后端服务使用Python Web框架:Django实现,主要方法有:
1.获取用户的uid信息,并验证uid信息,确保:
2.构建当日奖池;
3、初步确认用户中奖信息;
4、用户中奖信息审核;
5.将最终结果返回给客户端;
基本流程
1、用户通过Serverless Devs开发者工具在本地将盲盒抽奖客户端服务部署到用户自己的账户中;
在部署的时候需要给用户发放一个临时域名(这个临时域名需要用户的uid),Serverless Devs 在发放临时域名的时候会生成一个部分客户端token,记录在Serverless Devs的后端服务中,这个token其实就是识别用户身份的重要标识。
(若用户在YAML中声明不使用系统自动下发的域名信息,则可能无法成功参加本次活动)。
2.用户部署完成后会返回一个由Serverless Devs发放的临时域名,供用户学习和测试。
3、接下来用户通过浏览器打开临时域名,就可以看到抽奖的相关页面,用户点击即可参与抽奖操作。
4. 用户点击抽奖操作后自己做一个抽奖盲盒小程序,会向用户账号下的Serverless服务发起请求,服务根据用户的uid信息做相关处理,并向本次活动后端的Serverless服务发起实际的抽奖请求。
5.当本活动后端Serverless服务接收到用户的抽奖请求后,会:
获取用户账号下的Serverless服务发起抽奖请求时传递的uid信息;使用获取的uid信息去临时域名分配系统中匹配数据,判断用户本次使用了临时域名分配系统,并分配对应的域名;实现抽奖操作;
彩票核心实现
在抽奖运营过程中,我们也对现有系统进行了初步评估,并设置了简单、易于实现的抽奖功能,可用于小规模的抽奖活动:
关于这一部分,Django项目的实现方法是:
@csrf_exempt
绝对奖品(要求):
uid = 请求.POST.get(“uid”, 无)
如果不是 uid:
返回 JsonResponse({"Error": "Uid 是必需的。"})
temp_url = “?uid=” + str(uid)
如果 json.loads(urllib.request.urlopen(temp_url).read().decode("utf-8"))["Response"] == '0':
返回 JsonResponse({"Error": "Uid 是必需的。"})
令牌 = randomStr(10)
# 获得当天的奖品
奖品 = {}
对于 PrizeModel.objects.filter 中的 eve_prize(date=time.strftime(“%Y-%m-%d”,time.localtime())):
奖品[eve_prize.name] = {
“计数”:eve_prize.count,
“评分”:eve_prize.rate
# 建立彩票池
奖品列表 = []
对于 evePrize、prizes.items() 中的 eveInfo:
temp_prize_list = [evePrize,] * int((100 * eveInfo['rate']))
奖品列表 = 奖品列表 + 临时奖品列表
none_list = [无,] * (100 - len(prize_list))
奖品列表 = 奖品列表 + 无奖品列表
pre_prize = 随机.选择(奖品列表)
# 数据存储
尝试:
用户模型.对象.创建(uid=uid,
令牌=令牌,
pre_prize=pre_prize,
结果 = 假)
除了:
尝试:
如果不是 UserModel.objects.get(uid=uid).result:
返回 JsonResponse({“Result”:“0”})
除了:
经过
return JsonResponse({"Error": "每个人只能参加一次。"})
如果没有预奖:
返回 JsonResponse({“Result”:“0”})
用户 ID = UserModel.objects.get(uid=uid,token=token).id
users_count = UserModel.objects.filter(pre_prize=pre_prize, id__lt=user_id, date=time.strftime("%Y-%m-%d", time.localtime())).count()
# 最终决定是否获奖
如果 users_count >= prizes.get(pre_prize, {}).get("count", 0):
返回 JsonResponse({“Result”:“0”})
用户模型.对象.过滤(uid=uid,token=token).更新(result=True)
返回 JsonResponse({“结果”:{
“token”:令牌,
“奖品”:pre_prize
}})
系统安全设置
当用户中奖时,系统会生成一个 token,这个 token 和 uid 的组合就是判断用户是否中奖的重要依据。这可能涉及到一个问题:既然已经有了 uid,为什么还需要加 token 来做组合判断呢?其实原因很简单,如果直接通过 uid 来处理中奖信息的提交和查询ip形象,很有可能用户通过遍历等手段非法获取其他用户提交的信息,而这部分信息很有可能涉及到用户提交的收货地址,所以为了安全起见,加了一个 token,这在一定程度上增加了暴力遍历的复杂度。这部分的方法也很简单:
@csrf_exempt
def 信息(请求):
uid = 请求.GET.get("uid", 无)
token = 请求.GET.get("token", 无)
如果 [uid,token] 中没有:
返回 JsonResponse({"Error": "需要 Uid 和 token。"})
用户信息 = 用户模型.对象.过滤器(uid=uid,token=token)
如果 userInfor.count() == 0:
返回 JsonResponse({"Error": "尚未找到信息。"})
如果不是 userInfor[0].result:
return JsonResponse({"Error": "尚未找到中奖信息。"})
如果请求.方法 == “GET”:
返回 JsonResponse({
“结果”: {
“奖品”:userInfor[0].pre_prize,
“名称”:userInfor[0].名称,
“电话”:userInfor[0].电话,
“地址”:userInfor[0].地址
})
elif 请求.方法 == “POST”:
名称 = 请求.POST.get(“名称”,无)
电话 = 请求.POST.get(“电话”,无)
地址 = 请求.POST.get(“地址”,无)
如果 [姓名、电话、地址] 中没有:
return JsonResponse({"Error": "姓名、电话和地址是必填项。"})
用户信息.更新(名称=名称,
phone=电话,
地址=地址)
return JsonResponse({"Result": "保存成功。"})
整个过程如下:
通过用户的uid和token获取相关用户信息;若请求方法为GET,则直接返回用户的中奖信息(指发货信息);若请求方法为POST,则允许用户修改中奖信息(指发货信息);
其他安全补充:
如何保证token等用户信息的唯一性和不可伪造性,在浏览器端不太容易实现,因为用户可能会更换浏览器。但在函数计算平台的函数服务中相对容易实现。因此在域名发放阶段,记录指定时间段内发放的域名信息,然后后续进行比对,确保用户确实在规定时间内通过Serverless Devs开发者工具部署了项目、发放了临时域名、参加了活动。(当然,如果用户注册了多个阿里云账号,并参加了活动,也是允许的。)如何保证奖品不超发?这部分,系统采用了一个相对“笨”的方法,但也是小平台比较容易实现的方法。即先给用户一个奖品标记,然后根据用户奖品在数据库中的时间顺序位置判断最终的中奖信息。 例如,某用户中奖了一台机械键盘,数据库中是第6台机械键盘,但是总共只有5台机械键盘,所以会再次检查该用户的中奖信息,并标记为未中奖。(当然,这种做法对于小型活动是可以的,但对于大型活动就不行了自己做一个抽奖盲盒小程序,因为用户是否中奖会导致多次数据库读写操作,一定程度上是不合理的。)用户中奖后,提交了奖品邮寄信息,如何保证这些信息的安全卡通形象,防止被别人暴力遍历也是值得关注的问题,这里加入一个随机token,增加暴力遍历的复杂度,进一步保证安全;部署准备工作
本次部署不需要域名,可以使用函数计算生成的自定义域名,仍然需要安装 Serverless Devs 工具,本次只需要开通函数计算即可。
脚步
彩票后端部分模板还在准备中,只演示前端和数据层服务的部署。
步骤1:密钥配置
参考 Serverless devs 阿里云秘钥配置
步骤 2:初始化
使用serverless devs命令行工具执行:
初始化盲盒游戏
进入引导操作:
步骤 3:构建和部署
修改相关配置信息,执行deploy
效果图
功能部署:
页面效果:
抽奖部分的申请模板正在准备中,稍后会在这个申请模板中展示给大家。
结论
完成上面的实践之后,我想针对低代码和 Serverless 这个话题进行拓展,后面的部分会以理论为主,希望能给读者带来不同的收获。
从开发人员的角度看无服务器 + 低代码
而对于我自己来说,明确的结论是,我并不排斥二者的兼容,相反,我非常希望二者的结合能让我的工作更加高效,更加安全。
这次活动给我最大的感受是如果低代码平台能够跟 Serverless 无缝对接就好了。比如我在低代码上调用一个接口,只需要构建好上线再测试就可以了。这是天然一体化的平台非常明显的优势。还有就是前端发布构建好之后还要跟后端接口组装起来,如果是统一的平台,满足需求之后就可以一键发布,省去很多麻烦。但是这里也有矛盾,因为我也担心低代码前端一旦跟 Serverless 后端耦合起来,会变得不灵活,会被服务商锁定。
从供应商角度看无服务器 + 低代码
我们可以看到云服务商的Serverless和低代码服务正在不断融合,比如低代码平台的领军者Outsystem早在2016年就开始使用Lambda等AWS服务为其客户提供原生APP服务构建。
Trillo 是一个以 Serverless 和模型驱动应用为主要服务的低代码平台,帮助用户基于 Google Cloud Services 构建 Serverless 服务和前端应用。当然,国内外云厂商也忙得不可开交,Azure 将自己的低代码产品 Power Apps 与 Serverless 能力整合在一起,形成 Serverless Power Apps,充分结合了两者的优势。
AWS 将前端集成工作交给合作伙伴,更加专注于服务端的 Serverless 集成,并推出了 Step Functions Workflow Studio 产品,将 Serverless 与几乎所有自家产品对接。
国内腾讯推出了WeDa低代码平台,同样以Serverless+低代码为主打,主攻小程序场景,各家厂商的跟进也可见对这一领域的重视。
构建Serverless+低代码平台的思路
Serverless+低代码平台的价值是比较明确的,效率、安全、成本是它的关键词。那么如果我们要搭建这样的平台,需要做哪些考虑呢?
首先,在平台能力方面,应该能够覆盖应用开发从头到尾的各个环节。例如:
这里我们可以简单解释一下这个平台的功能设计,并基于云厂商的基础设施构建相应的能力。
目前有一些与低代码能力相关的开源产品,在这里可以分享给大家:
另外,在对接云基础设施的时候,可以考虑使用 Serverless Devs 的 Iac 能力,特别是目前与 FC 集成的成熟度较高,可以轻松管理函数的全生命周期。
当然,以上只是作者的一些想法,我深知实现这样的系统并不容易,这些只是一些可供参考的想法。
追求生产效率的提升一直是企业生产中的重要话题。Serverless 和低代码在各自的技术领域有着独立的分工,但也有着提升生产效率的共同特点。学会同时掌握和用好这两款生产力工具或许是信息行业从业者重要的竞争优势。
原文链接