首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >同一条通知要发三个通道,模板和变量该怎么设计才不重写?

同一条通知要发三个通道,模板和变量该怎么设计才不重写?

原创
作者头像
小小码农爱奋斗
发布于 2026-11-15 11:14:19
发布于 2026-11-15 11:14:19
50
举报

一、同一件事,三份文案改了三遍

补贴公示这个通知,我们在三个地方各写了一份文案。村委会的公示栏用 A4 打印出来贴在墙上,写的是「张三户于 2024 年 3 月 12 日领取补贴 2400 元」。给村民发的短信是一条纯文字,写的是「您的补贴已发放,请查收」。村务平台站内信又是第三种,写的是「您有一条补贴发放记录待查看」。三份文案在三个后台页面里改,改一次要改三处,漏一处就对不上。

去年十月出了一次实的事。补贴标准调整,补贴金额从 2400 改成 2600,通知模板改了这一处。结果短信发出去的还是 2400,因为短信那段文案压根没改,是另一份手写文本。村民拿着短信去问,村干部解释了半天。发出去的短信收不回来,解释的成本落在了村干部身上。

还有一次是渲染报错。有一条通知的模板变量里写了「${ villageName }」,模板里没有这个变量,渲染出来的是一段乱码样式的原始文本,站内信里显示成了「${ villageName }村补贴公示」,直接展示给了村民。整批 46 条通知都这样,用户在后台看得见乱码,投诉当天就来了两个。

还有一条更麻烦,同一份模板在上个月改过之后,之前发出去的通知内容也变了。用户翻出去年的通知记录,发现当时写的金额和现在模板算出来的不一样,只好把模板回滚回去重算,运营那边一阵手忙脚乱。

四件事指向同一个判断:通知这件事现在缺的不是渠道,是模板。三个通道各写各的文案,改一处漏一处;变量在渲染时才校验,出错已经发到村民手里;模板一改,历史通知跟着变,通知本来是留痕的东西,被改得没法留痕。

二、通知是渲染产物,不是三段文本

把通知这件事拆开,它的结构是四层。模板是骨架,规定这段通知由哪几部分组成、每部分写什么。变量是占位,标明哪些内容要发的时候才知道。渲染是把模板和变量合成成成品文本。发送是按通道各自的限制把成品送出去。现在的问题是这四层里,模板这层被架空了,短信那段其实是手写文本,站内信那段是硬编码在代码里的字符串。

直觉做法是每种通知类型写一个函数,参数就是那几项内容,函数里拼字符串。这条路在小规模下很省事,代码里一眼能看到发出去的是什么。代价是每个通道一份拼法,同一事项三份拼法,任何口径调整要改三个函数,拼出来的长度也不受控,短信超长被截断之后用户看到半句话。

另一条直觉做法是硬编码成完整的成品文字,不做模板不做变量。有几个通知类型确实是固定的,比如系统维护公告,那一个硬编码就够。可业务类通知的内容是跟着数据走的,姓名、事项、时间、金额、链接这些个位数就能描述完的东西,值不值得为它建一套体系,取决于这类通知的量。

所以真正的判断标准是量。固定文案走硬编码,业务文案走模板,判断清楚这两类的边界在哪,比纠结用哪种技术方案有用。补贴公示、事项办结、矛盾调解通知这些是业务文案,走模板;系统公告走硬编码。

三、两条路和各自的代价

第一条路是每种通知类型配一份模板,每份模板固定对应一个通道,通道之间各写各的。这条路的实现最简单,一个模板表加一个渲染函数就够。代价是内容重复,同一事项的三个通道三份模板,改文案要改三处,三处说的是不是同一件事根本拦不住,短信里写 2600、站内信里写 2400 这种事挡不住。

第二条路是一份模板多通道渲染。模板定义的是结构,变量是数据,通道负责各自的呈现和限制。短信通道渲染成纯文本,站内信通道渲染成带链接的卡片,推送通道渲染成短标题加摘要,三种呈现从同一份结构和数据出来。代价是模板结构得设计成能同时满足三种呈现,链接在短信里要变成短文本、卡片里要变成可点按钮,这就要求模板作者懂一点各通道的脾气,管理成本比第一种高。

我们选第二条。这个县里业务类通知一年发两万三千多条,其中 71% 是同一类事项的三个通道版本。模板数量从三十多份降到十一份之后,改文案这件事从改三处变成改一处,短信和站内信对不上的问题从结构上消失了。

四、一份模板三端渲染,短信按字数截断

万村乐数字乡村的通知模板带变量渲染,短信通道单独按字数截断规则走。模板用一段带占位的文本表示,变量语法是双花括号加名字,比如姓名写作 {{ name }},事项写作 {{ matter }},时间写作 {{ happenTime }},链接写作 {{ detailUrl }}。变量名用驼峰,和后端字段名一致,不用映射表。

模板的骨架部分带条件块,同一段内容在短信通道可以不出现。写法是双花括号包一个 if 条件和一个 else,比如只在站内信和推送出现的一段用短信不显示的条件包起来。这个能力在链接那块用得最多,短信里放链接要么被拦要么占字数,就用条件块让它在短信通道消失。

变量渲染之前先做一次校验,校验在发送之前,不在渲染之后。校验查两件事:模板里引用的变量在这次的数据里有没有,变量值是不是空。空值走三种策略,必填为空直接终止这次发送并把原因落到通知记录,可空则渲染成空字符串,可空且有默认值的用默认值兜。这三种策略在模板里逐个变量配,配在变量定义上,不配就用可空的默认策略。

短信通道有单独的字数截断规则。短信单条上限 70 个字符,超出按规则截断,规则是:先砍掉条件块里已被标记为可裁剪的内容,标记为不可裁剪的正文绝不动,砍完还超就整个短信放弃转成站内信。宁可换通道也不发半句话,这是我们讨论后定的。

发送环节的顺序是模板版本、变量数据、通道规则、渲染、发送。模板版本在渲染之前就锁定了,渲染用的是发出去那一刻的版本,不是数据库里当前的那一版。这个锁定是解决历史通知被改的关键,锁定动作发生在发送记录落库的那一刻。

五、模板结构、版本和校验的细节

模板表里几个关键字段。templateKey 是模板标识,bizType 是业务类型,channelScope 是适用通道,version 是版本号,body 是模板正文,variables 是变量定义,里面逐个变量记名称、是否必填、默认策略、是否可裁剪。通知记录表里存 templateKey、version、renderedContent、channel、status、failReason,renderedContent 存的是渲染后的成品全文。

模板版本管理是这套东西里最要紧的一块。改模板不是直接改,是生成新版本。已发通知记录里存着当时的版本号和渲染后的全文,模板后来怎么改都动不了它们。版本号用整数递增,同一个 templateKey 下的版本号不重号,回滚是把当前版本指回老版本,不是删老版本,这样历史通知查出来的还是它当初的那个版本。

预览是一个独立的入口,填一份假数据就能看到三个通道各自渲染出来什么样。预览走的是同一套渲染函数,不另开一条预览专用逻辑,早期版本预览和实际发送不一致,害得我们白改了三轮文案。

六、三个坑和它们的代价

第一个坑是变量在渲染时才校验。那批 46 条带乱码的通知就是这么来的,模板里引用了不存在于数据里的变量名,渲染函数拿不到值就把占位符原样吐了出去。根因是校验环节放在渲染之后,渲染函数被设计成对缺失值宽容。改法是把校验提到渲染之前,缺失的变量分成必填缺失和可选缺失两种,必填缺失直接终止发送并落原因,可选缺失按默认策略补上,模板预览那一步就会把这些标出来。

第二个坑是短信截断把链接也截了。短信正文里带一个详情页链接,链接加上正文超过了 70 个字符,我们的截断规则原来是从末尾硬切,链接被切掉一半,用户点进去报页面不存在。根因是截断没有区分可裁剪和不可裁剪。改法是给变量打上可裁剪标记,截断时优先裁可裁剪的段落,实在裁不动就转站内信,不发半截短信。

第三个坑是改模板把历史通知改了。补贴标准调整那次,模板正文里的一处金额计算改了,去年发出去的 1200 多条通知记录里的正文也跟着变,用户翻记录发现金额对不上。根因是通知记录存了模板标识,没存版本,渲染的时候按当前模板重算。改法是记录表增加 version 字段,渲染出来的全文直接存进记录,查询历史通知读的是存下来的全文,不重新渲染,模板改成什么样都碰不到它。

七、这套做法管不了什么

模板体系管的是文案结构和变量填充,管不了发出去之后的事。短信被运营商拦了、推送被系统折叠了、站内信没人点开,这些是送达和触达的问题,模板这边只能管住送出去的那段文字本身对不对。我们统计过送达率,模板改动前后送达率的波动在 2% 以内,可见这两件事关系不大。

也管不了文案的合规审核。模板能让审核的人更容易看出哪里是变量、哪里是固定文字,但审核流程本身不在模板这一层,一个写错了的固定文字照样能过审。

还有一处边界是通道本身的限制。短信的 70 字符是硬限制,推送标题的 20 字符也是,这些限制各有各的规则,模板条件块能绕开一部分内容,绕不开的比如一个不能删的短链接,超了就只能换通道,模板体系能做的只有识别这种情况并转走。

八、回头看这套模板体系

模板加变量这套体系在万村乐数字乡村里统一了三类通知通道,文案只维护一份。改造完成后的第一个月,补贴公示这类通知因为文案不一致引发的投诉是零,之前这类投诉平均每月四起。短信被截成半句话的情况也从每月二十多条降到零,全部按规则转成了站内信。

回头看这件事,收益最厚的一次不是省下了文案维护的时间,是把「改文案要改三处」这个动作变成了「改文案只改一处」。改一处才可能改对,改三处永远是三份不一致的风险,这是结构问题,靠人的细心顶不住。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档