打码指南:由猫眼线下扫码1分购谈起 | 掘金直播小程序专场总结

2,215 阅读16分钟

背景

大家好, 今天给大家分享的是打码指南, 由猫眼线下扫码1分购谈起.

小程序在发布之后是没有入口的, 之后确定是由线下扫二维码进入, 今天分享的是我们自己尝试在下线投放二维码, 进行促销活动, 中间经历了一些波折. 这里给大家介绍一下中间经历的事情.

先做下自我介绍, 在2015年加入美团之前, 一个是去哪儿, 一个是CSDN, 再之前在西安, 主要是外包项目, 企业信息管理系统. 之前在做Java, 当时没有前端工程师的岗位, 但日常工作做前端比较多, 后面大家会看到有时有前端, 有时没有前端的介绍, 这是因为我个人准全栈的经历导致. 如果有志向做PM的话, 也建议关注下, 因为一个好的PM, 你应该知道这个东西是怎么工作起来, 都有哪些人参与, 每个人负责什么东西, 这个也是很有帮助的.

回到主题, 我们今天大概介绍这4个点

  • 小程序码和二维码的约束
  • 产出物料后修改需求
  • 优惠券和用户触达通知
  • 线上监控发现的问题

第1点和业务无关, 纯技术的描述. 因为后面在介绍业务相关的场景的时候, 为了说的更流畅, 所以需要先介绍下小程序码和二维码的约束.

小程序码和二维码的约束

类似菊花那种, 官方名字叫小程序码, 我们在日常沟通当中不会在意这个细节, 反正都能扫, 都叫二维码.

方案A: getWXACode

这是微信文档有这个API, 用于生成这个二维码, 参数包括

path: 'pages/movie/index?arg=foo'

限制:

  • path参数限制128字节长度
  • 调用总数量限制: 10w个, 如果超过微信会拒绝后续的接口请求, 直接出错, 提示超量

方案B: getWXACodeUnlimt

仍旧是菊花码, 参数包括

path: 'pages/movie/index'
scene: 'arg=foo'

限制:

  • path 不能加query参数
  • scene 长度限制32个字符

在业务场景中不是很通用, 只能固定落地页, 但是我们扫码的目的还是需要有一些线下的特点能够传过来, 如果使用scene参数传递额外参数的话, 这个限制比上一个更苛刻, 但是它不限数量.

这个是在多数大规模投放二维码的方案, 小规模的, 比如我们的今天要讲的这个案例, 我们投放了大概2000多个影院, 其实这2个方案都可以.

方案C: createWXAQRCode

小程序官方叫小程序二维码, 看起来和普通二维码差不多, 由于二维码本身有一定容错能力, 所以LOGO放着是没问题, 参数

path: 'pages/movie/index?arg=foo'

限制:

  • path 128字节长度
  • 调用总数量限制: 10w个, 和方案A公用配额

这个二维码可以用普通扫码程序扫描, 扫码之后可以发现地址是 mp.weixin.qq.com/a/xxxxxxxxxxx, 这是一个有意思的地方, 我们明明给传的是上面的参数, 但是生成的是下面这个地址, 感觉是做了转换.

前面介绍几种形式, 限制和支持的参数, 存储的信息, 本质上这些信息和URL差不多. 我们用二维码连接线上线下, 二维码本身存储的信息是路径加参数.

传统web开发我们需要关注URL上的输入信息, 比如query参数, 路径, 特别是单页应用的路由框架特别关注URL上的信息.

可以理解URL也是一种输入, 类似触控. 所以二维码也需要前端的同学关注, 因为我们要去处理二维码背后的参数, 和我们的期望是否能匹配.

接下来看下实际案例, 和遇到的问题.

领取优惠券后, 期望能点击后退

我们在线下投放的业务, 通过易拉宝的形式, 扫上面的二维码, 进入活动落地页, 登录支付1分钱, 领取两张优惠券, 分别用于支付电影和小吃如爆米花时抵扣. 投放位置是电影院, 我们的主要合作方.

需求第1阶段

5块的优惠券不是凭空出来的, 是得有人承担的, 一般是平台和商家互相分摊的. 平台期望活动越多越好, 但是影院是有限度, 因为影院的规模, 活动成本有要求. 因此我们必须要识别出来是那家电影院, 涉及到财务结算, 不能错.

我们的方案:

  • 活动页每家电影院带上影院参数, 每家影院生成不一样的二维码
  • 我们还需要打印出来

问题来了, 我们有2000家影院, 每家比如需要2份物料, 那么我们需要打印4000份, 有2000种不一样的二维码.

物料一般是总部生产, 因为多数公司比较在意自己的品牌, 不会允许地下城市自己随便生产涉及品牌形象的物料. 总部制作好之后还需要邮寄到各个城市, 把它放到具体的影院中.

正确的打印和邮寄, 人工不出错才见鬼了. 快递还可以直接看单子, 二维码人不能直接识别, 打印错了也难以发现.

所以直接按照这个方案走是很容易出错的. 1%的出错比例影响也比较大, 出错的影院会直接找上门, 那就会是很大的麻烦.

为了避免出错, 调整之后的方案, 我们印刷一个模板, 不包含二维码, 因为物料只有二维码部分是变的, 别的都不变, 这样就可以批量的印刷, 批量的邮寄的问题. 如果邮寄出错了, 我们可以把电子版素材发过去, 在当地印刷出来也来得及, 也允许电影院自行印刷更合适的介质.

二维码通过影院后台推送, 影院自行粘贴, 这也是大家看一些大型活动二维码和背后的物料是分离的原因.

看起来没啥问题, 实际落地效果基本符合预期. 但接着就进入到一些更具体的业务场景

需求第2阶段

进入活动落地页, 完成简单任务或直接领取优惠券, 领取优惠券之后期望支持后退, 如果我们什么额外的都不做, 左上角什么都没有, 没有后退, 只能点右上角关闭, 再进来又是活动页.

用户就会疑问, 我领了优惠券到哪里去花呢?

所以需求肯定会要求支持回退, 跳转到能消费优惠券的地方. 之前在掘金小程序开发者大会当中有讲师也提到过, 左上角的后退按钮对用户体验和数据的提升很重要的, 前端就需要考虑怎么实现这个需求.

最笨的办法: 先到首页, 首页再做一次重定向到活动页, 一般我们期望后退到首页.

另一个方案是自定义导航, 相当于页面是全屏的, 只是在右上角浮出2个小程序自身的按钮, 关闭和菜单按钮. 但这个方案有一些限制, 我们最后没有用这个方案.

使用第一个方案的话, 二维码变了, 虽然没超过128字节, 但已经印刷的二维码就不能用了, 这就麻烦了, 还得重新生成二维码, 重新印刷, 并粘贴上去.

如果真的是这样走一步看一步, 走到这肯定出问题, 肯定会吐槽.

更多需求

实际不仅仅如此

  • 期望能后退到别的页面
  • 一家影院在不同入口放置的二维码效果如何?
    • 期望知道影院入口的效果
  • 参数越来越多, 长度超限怎么办?

类似的需求越多, 参数就会越多. 如果是方案B的二维码, 参数限制只有32位, 如果是方案A, 总长度128能稍好一些, 但反复生成二维码很有可能超过10w个数量限制.

最终会发现产出物料后改需求是一个常态, 我们如何才能支持这个常态.

短网址服务

这时就回到了我们提到的那个有意思的方案C, 我们提交的参数是一个地址, 但它生成的二维码实际存储的是另外一个地址, 很像短网址服务有没有. 我们是不是也可以做一个这样的服务, 客户端的方案如下

  • 入口: path: 'pages/jump?id=3a5fc8', id参数表示一个短网址的id, 这个用于生成二维码
  • pages/jump 页面
    • 请求后端 wx.request({ url: 'xxxx', data: '3a5fc8' })
      • 期望获取到 { path: 'pages/movie/index?go=pages/onecent/index?cinema=15280&utm_source=foo' }
    • wx.redirectTo({ url: path })

这个 path 就没什么长度限制, 这样就可以完美的控制后退导航行为, 以及增加类似 utm_source 的埋点参数, 用于跟踪放在影院的不同入口扫码意愿的差异.

做这些需要前端 后端 PM整体协商合作.

接下来看看服务端我们期望它有什么功能

  • 创建短网址 API: 因为我们会批量创建
  • 批量查询和修改 API: 因为是批量创建的, 我们又有产出物料后改需求的常态
  • 短网址的额外信息
    • 类别: 同一活动属于同一类别
    • 附加信息: Map结构, 比如包含 影院ID, 后退的页面地址, 埋点信息等, 为了通用性

最终我们生成的二维码包含的 path 信息是: pages/jump?id=3a5fc8, 我们只需要到短网址服务后台修改就可以控制它的行为.

更多

这个方案需求是解决了, 但由于多了个中间页, 可能界面是白的, 最多加个loading态, 改善下体验, 但时间上可能会有点问题, 比原来要慢些.

一般的解决办法, 首次进入缓存, 第2次进入直接使用缓存数据, 但仍旧发一个请求出去, 响应了再更新缓存, 这样无论缓存过期还是别的状况, 请求都不会阻塞.

更进一步, 我们可以生成一个http的地址, 其它的程序也能扫码成功, 不限于微信.

http://m.maoyan.com/jump?id=3a5fc8

比如我们期望使用一个二维码, 任何终端扫码都能进入活动. 我们期望微信扫码打开小程序, 这样体验更好, 其它程序扫码打开h5页面.

微信扫普通二维码能打开小程序, 这个能力来自小程序管理后台, 叫"扫普通链接二维码打开小程序", 只需要配置一个URL模式, 模式限制数量10个.

有些公司可能小程序公众号参与者权限互相有隔离, 所以实施这个会有一些沟通工作.

小结

  • 需求是多变的: 基础需求, 后退, 埋点等诉求, 这是一种常态
  • 物料产出后难以修改: 随着需求变更而重新生产物料是不现实的
  • 短网址服务: 最终的方案

我们现在已经能让用户扫码, 进入活动页, 领取优惠券, 后退回到首页, 完成购票流程.

但不是所有用户都会走购票流程, 比如用户现在想去吃饭, 就会关闭小程序走了, 这种情况我们 就只能等用户来购票.

显然我们不能等用户来购票, 这样在体验上还是差点, 用户领取了优惠券, 但是没有消费是我们不愿意看到的.

优惠券和用户触达通知

我们期望用户领了优惠券之后能通知用户, 方案有两种

  • 微信支付优惠券
  • 自建优惠券

微信支付优惠券

微信支付 预充值代金券

  • 入口: 消息列表 "微信支付" 服务号
  • 时机: 领取时, 即将到期时
  • 满减 商品限制 预算限制
  • 防刷 对账 消耗记录

需要先充值, 会占用一些现金, 有做PM的同学需要注意这点

前端需要注意商品限制, 有这种限制的时候, 需要前端把商品标记传给微信支付API

自建优惠券

有些公司可能不太愿意提前垫付资金, 这样对现金流有要求, 那么就可能需要自建优惠券.

如果要做到类似微信支付优惠券的体验, 我们需要做

  • 入口: 消息列表 "服务通知"
  • 时机: 自由
  • 满减 限制商品 预算限制
  • 防刷 对账 消耗记录

限制

  • 要使用服务通知, 所有消息都需要凭证, 凭证通过表单 form 标签 和支付能收集到, 也就是用户必须有点击行为, 7天有效期
  • 前端需要刻意在小程序上尽量收集这些凭证, 因为需求是多变的, 可能一开始说发2次就行, 后续又说需要发4次
  • 客诉, 用户觉得骚扰, 会给微信投诉, 微信会直接删除消息模板, 消息就发不出去, 投诉再多就可能触犯了小程序的规定, 有封号可能
    • 一定要告知给PM, 特别是业务流程需要这个通知, 一定不要做违规的试探行为
  • 防刷 对账对于后端来说工作量还是很大的

小结

自建优惠劵需要做的工作很多, 初创公司建议直接使用微信支付优惠券, 特别是合规 防刷 对账

自建优惠券, 前端需要注意多收集凭证, 通过 form + button

线上监控发现的问题

至此, 我们的活动上线, 用户领了优惠券后, 既能现场买票, 也可以过一段时间收到通知, 得知还有优惠券可以去买票.

上线后还需要观察服务本身有什么意外, 由于我们对于多数的异步调用都做了监控, 所以...

无法完成登录

wx.getUserInfo() 的返回中包含 signature: 签名参数, 正常流程是返回了用户昵称 头像信息后需要进行数字签名并比对是否一致, 不一致就表示有问题, 一般是认为获取用户信息失败.

但实际中发现Android 5.x系统下的微信客户端, 如果用户昵称中如果包含 emoji 字符, 那么 signature 肯定不一致. 此时用户昵称中的 emoji 字符实际ASCII值为 0xFEFE 这样的字符, 一般看起来是乱码.

解决方案: 除了等android 5.x基本消失, 就是如何符合上述条件, 可以忽略这个数字签名比对, 昵称只能获取到个大概, 基本够看.

任何微信接口调用可能失败

我们调用了很多微信的接口, 比如 wx.login 相关, 生成二维码. 有时会超时, 小程序端上的表现是卡顿, 隔了很久提示网络错误, 偶发, 很难复现, 大概0.5%.

对于百万以上日活用户的app来说, 这个问题还是挺严重的, 有些用户如果点击后发现没响应, 就停在这了, 用户会认为你的小程序有问题, 直接关闭退出了.

调研的结论是网络问题, 微信这边给的方案是尝试用 api2.weixin.qq.com, 也就是我们需要实现一个容灾 重试策略.

我们最终实现了一个延迟重试的策略, 上线后调用微信接口的可用性从 99.5% 上升到 99.99%+.

cat监控系统

我们用过的一些异常收集系统, 或者在系统出问题的时候, 收集系统也挂掉了, 或者不够实时, 或者没有合适的分类, 只见树不见林, 无法知道整个问题的情况, 不容易抓住重点.

我们发现上述问题主要依赖一个叫cat的系统

github.com/dianping/ca…

基于java, 吞吐量 负载能力超强, 分类聚合满足需求

总结

  • 我们介绍了小程序二维码的约束
  • 需求变化导致我们需要支持产出物料后改需求, 我们通过短网址服务来支持这个业务
  • 我们期望促销活动能产生用户消费, 需要通知用户使用优惠券, 介绍了两种方案的利弊, 成熟的公司可能两种方案都要支持
  • 上线的异步调用 远程调用监控, 发现的2个问题及其解决方案.

回顾下标题, 打码指南: 由猫眼线下扫码1分购谈起, 靠谱的线下扫码活动需要技术团队提供那些支撑.

我们讨论了需要开发什么样的系统, 关注什么流程, 那些约束条件需要周知给各方. 因为前端所有的工作都是在一个宿主环境下, 都有很多的限制, 我们需要在各种限制的条件下完成各种需求.

Q&A

  1. 为什么没有使用自定义导航栏的方案

自定义导航栏, navigationStyle: custom 1.9.5 开始支持, 但需要 整个小程序 所有页面都自定义导航栏才行, 这对于我们的场景不太适用, 只能作为长远打算

  1. 能讲下延迟重试策略么?

根据我们的监控统计, 请求微信的接口95%的都会在650ms内响应, 大于这个时间最终请求超时的概率就很大了, 所以最终策略是

一旦请求在650ms内未完成, 立即发出后备请求, 直到任意一个获得响应, 并且是正确的响应内容

这个策略我们开发成了一个superagent插件, 后续会考虑开源出来

  1. 这么看做线下扫码活动成本 门槛还是有点高, 有什么别的方法能减少这方面成本?

我们最初还考虑过另一种方案, 可以通过定位, 让用户选择附近商家, 会在体验 运营自由度上有折扣, 但可以规避各种二维码物料的问题.

不过最后还是没有用这个方案, 如果可接受体验上的折扣, 还是可以用这种方案的.

其次就是把上文提到的二维码相关功能做成服务开放出来, 我也有关注提供这方面支持的互联网产品, 目前看未有发现.

上面的文字版的总结,也推荐大家如有时间的话观看原版视频分享,现在已经上传到了 Bilibili,链接为:www.bilibili.com/video/av348… ,欢迎大家观看学习和收藏~