本文介绍为免费评论系统 Valine.js 增加新回复邮件提醒的方法。使用 node.js 借助 nodemailer 实现。引擎使用 Valine 所使用的 LeanCloud Serverless 云引擎。
对于不会使用 node.js 的用户也没关系,只需要把本文中 编写 LeanCloud 云函数 一节中的代码简单修改(加入您的邮箱和网址),再按下一节的指引操作部署,就可以实现有新评论时,评论者和站长都收到邮件提醒。
什么是 Valine.js
Valine.js 是我非常喜欢的评论系统,正在本站中使用。这个系统有以下几个优点
- 不需要用户登录即可评论
- 中国大陆可用
- 基本免费,无广告
- 没有繁杂的后端管理系统
- 界面现代美观且可订制
- 部署非常方便
在具有以上优点的同时,也随之而来一些缺点
- 没有评论审核,会产生垃圾评论,需要用户手动处理
- 只适合小型网站,评论量不大的情况
- 没有评论提醒功能,需要到数据存储中查看
下面针对第 3 点问题,提出解决方案,即为 Valine 评论系统加入邮件提醒功能。
Valine 的工作原理
Valine 的数据存储在 LeanCloud 上。LeanCloud 是一个 Serverless 服务平台,可提供强有力的 Serverless 后端支持。其开发版本的数据存储和云引擎功能在一定条件下是免费的。而这个免费的额度足够一个小型网站使用。因此说 Valine 是基本免费的。
关于 Valine 的配置,请移步其 官网文档 ,这里不再赘述。
在 Valine 配置完成后,我们会发现,它在 LeanCloud 的云存储中建了一个新数据表,名为 Comment
,里面记录了每一条评论的信息,主要包括
1 | { |
这些信息可以通过 LeanCloud 提供的 API 来获取。LeanCloud 的 cloud-storage API 提供了多种语言的调用方法,详细使用方法可以参考其官方文档,这里可以暂时跳过。
使用 LeanCloud 云引擎
上一节介绍了 Valine 使用的云存储。下面我们来介绍云引擎。云引擎是 LeanCloud 提供的真正 Serverless 后端,同样支持多种语言。
云引擎还支持多种调用方法,包括钩子(Hook)函数和定时函数。其中钩子函数是在云存储发生改变的时候激发的。定时函数是在定时器达到条件时激发的。下面就使用云引擎的这两种调用方法,来实现评论的邮件提醒功能。这里我们以 node.js 为例。
使用 nodemailer 发送邮件
本节介绍 nodemailer 的使用方法。如果您不感兴趣,或者本地没有安装 node.js,可以直接跳到下一节,不会影响您的应用部署。
nodemailer 是一个 node.js 的邮件发送引擎。下面我们介绍其使用方法。
在使用之前,先来找一个发送邮件使用的 smtp 服务器。这里介绍使用 QQ 邮箱 smtp 服务器的方法。
登录 QQ 邮箱,进入 设置
> 账户
,其中有一项“POP3 / IMAP / SMTP / Exchange / CardDAV / CalDAV 服务”,在 IMAP / SMTP 服务一项,选择 开启
。开启之后,在下方找到 生成授权码
,根据提示,生成授权码,并复制下来。这个授机码就是在 app 中使用的邮箱密码。假设它是”shouquanma”。这时,IMAP/SMTP 服务设置完成。
下面,在系统中配置好了 node 和 npm 之后,安装 nodemailer
1 | npm install nodemailer |
下面我们来测试一下。创建一个文件 app.js
,写入
1 | function app(request) { |
这里先定义了一个函数 app
,这个函数返回了一个 Promise
。对于 javascript 异步操作不熟悉的朋友,这里推荐Promise 迷你书。然后在主进程中调用这个函数返回的 Promise。我们来测试一下,在控制台中输入
1 | node app |
可看到,控制台中提示发送成功,邮箱里收到了发送的测试邮件。如果不成功,请注意是否修改了正确的发送邮箱,并查看控制台输出的错误原因。
以上是 nodemailer 最简单的使用方法。对于更多的使用方法,请参考其 官网。
学会了使用 nodemailer 后,我们来写云函数。
编写 LeanCloud 云函数
下面我们创建 LeanCloud 支持的云函数,如果您对 node.js 不熟悉,不需要理解其内容,只需要复制下来,把发件邮箱、邮件内容相应修改即可。直接看代码。
1 | var sendEmail = function(request) { |
其中,AV 是 LeanCloud 的云存储提供的 SDK 所封装的对象,它提供了查询方法
1 | Query(class_ : string).get(objectId : string) -> Promise |
等一系列云存储的 API 方法,可参考文档。
request
是函数的参变量, request.object
代表发送来要存储的那条记录。
下面把以上代码部署到云引擎中。
部署发送邮件的云函数 Hook
云函数是云引擎调用的函数。它支持使用 git 部署,也支持在线编辑。这里我们为了方便,选择在线编辑。
首先,登录到 LeanCloud。在配置 Valine 时,已经创建了一个名为 vcomment
的 app,在网站控制台的卡片中点击这个 app 的“云引擎”图标,进入云引擎的管理页,找到 部署
选项卡,看到部署状态为“未部署”。有两种部署模式可以选择,我们选择 在线编辑
,点击进入。
下面点击 创建函数
,弹出在线编辑对话框。类型选择 Hook
,Class 选择 Comment
,表示每次调用函数时,就发送一次 email。然后在内容部分,可以看到,函数的定义部分已经写好:
1 | AV.Cloud.afterSave('Comment', async function(request) { |
我们把上面定义的函数(去掉首行和尾行)复制进去。点击 创建
,云函数创建完成。然后点击 部署
,弹出日志对话框,提示部署完成后,发送邮件的功能就已经配置好了,可以到网页中尝试。
由于 LeanCloud 的免费版云引擎有休眠策略,每半小时都会休眠一次,而且休眠唤醒时需要数秒钟时间,所以如果不使用付费版的话,需要进一步处理。这里提出两种解决方案。
第一种是在浏览器端绑定点击事件。当用户点击了评论输入框或回复按钮时,向服务器发送一个请求,以唤醒服务器。
第二种方案是设置定时任务,每隔一定时间,如 1 小时,或每 1 天,检查一次是否有新的评论产生。如果有新的评论,把它们按收件人汇总后,统一发送邮件。
第一种方案适用于评论用户比较少的情况,第二种适用于评论较多的情况。我的网站采用的是前者。下面对两种方案一一介绍。
使用 HTTP 请求唤醒服务器
首先创建一个可调用的云函数,与前面创建方法相似,不过在函数类型中选择 Function
,用于浏览器调取。这里我们把它命名为 wakeUp
。内容很简单
1 | console.log('Cloud function wakeUp is triggered.'); |
这样,在调用函数时,返回一个 “Hello” 字符串。然后我们在使用了 Valine 的网页中,为评论区域添加一个事件,当评论框被第一次点击的时候,调用这个云函数,以唤醒服务器。在页面的 html 中加入以下 script 标签
1 | <script> |
基本思路为,为Valide所在的
onclick
事件,当第一次点击时,调取一次 wakeUp
云函数,即激活了服务器。这时,您的邮件系统可以完全正常运行了。如果服务器休眠,只要用户用心评论(撰写时间达到数秒),也不会受到影响。
使用定时任务部署 LeanCloud 云函数
免费版的云引擎不但会自动休眠,而且每天的工作时间不能超过 18 小时。这对小流量网站来说足够使用了。但是如果评论数很多,可以选择使用定时任务部署,比如每隔一个小时,或在每天的早上 9 点,把之前的所有评论发到邮箱中,或者每月把统计数据发到站长邮箱中。这里给出方法,请有需要站长们自行补全。
先定义一个云函数,用和上一节相似的方法。函数体中一个主要变化就是需要根据日期查询所有的评论,这时我们借助 Moment.js,在每天早上查询前一天的所有评论。
1 | AV.Cloud.define('archiveComments', async function (request) { |
这个函数创建完成后,再到网页控制台中,找到 定时任务
,单击 创建定时任务
,选择刚才的函数,在 Cron 表达式中输入
1 | 0 0 9 * * ? |
6 个项目分别表示:0 秒,0 分,9 时,任意日,任意月,任意星期。 Cron 表达式可参考这篇文档。保存,即可。
如果定时任务也遇到了休眠的问题,可以参考上一节,在定时任务执行之前几分钟,再增加一个定时唤醒任务 wakeUp
,问题就解决了。
转载请注明:本文转自翰林苑(http://www.hanlindong.com),原作者:董翰林。