最近,博客上线了点赞功能。使用的是MongoDB+腾讯云云函数的方式,整个功能使用的组件全部是免费。
下面,跟随本文的脚步,也给你自己的博客添加点赞功能吧!
源代码:
- serverless后台:serverless_blog_like
- 前端样式:Twitter红心点赞CSS3动画按钮特效
使用mongodb和serverless给你的博客添加点赞吧
前言
很久之前就有给我的博客增加点赞功能的想法了;
相比于评论和打赏,点赞基本上是一个轻量级、接近零成本的方式给与读者的参与度;
正好腾讯云有免费的FaaS产品云函数SCF、MongoDB官网有提供免费的分布式DB可以用,就花了两个小时给我的博客加了个点赞的功能;
FaaS后台
① mongodb存储
整个后台部分使用的是mongodb官方提供的免费mongodb存储;
首先进入mongodb官网:https://www.mongodb.com/
点击中间的Start free
:
注册账号后就有一个免费的分布式mongoDB可以用了!
mongodb的管理界面如下图所示:
点击Collections即可查看存储的数据;
点击Connect即可查看连接mongodb的各种连接方式;
在这里我们需要记住在
Connect your application
中的连接方式;如果你是用的是node,则连接方式如下:
mongodb+srv://<username>:<password>@cluster0.atob4.gcp.mongodb.net/<dbname>?retryWrites=true&w=majority
稍后我们需要使用这个连接我们的mongodb;
由于mongodb是不需要提前创建表和表结构的,所以我们直接进入后台serverless部分;
② 创建云函数
进入腾讯云云函数SCF:
https://cloud.tencent.com/product/scf
点击管理控制台进入(如果你还未开通,这里首先会开通云函数服务,然后再进入云函数SCF控制台);
进入控制台之后大概是这个样子的:
点击函数服务,进入函数服务页面并点击新建:
进入新建页面后,填写一个函数名称,例如:BlogLike
;
并选择运行环境Nodejs12.16。这里我选择的是NodeJS环境,因为JS操作mongodb更方便一点,也更容易写;
(如果你对Java或者Go比较熟悉,也可以使用对应的环境)
最后选择空白函数,并点击下一步创建:
函数配置全部保持默认,点击完成即可创建函数;
函数创建完成后,腾讯云会提供一个hello-world的示例:
从示例中可以看出,整个函数的入口是:index.main_handler
通过下面提供的接口测试,也可以查看到具体的参数是在event中的;
这里我们不使用提供的模板,而是自己创建一个node项目,并使用index.main_handler
作为服务函数入口地址即可;
③ 编写后台服务
使用npm init
创建一个项目,并引入mongodb的依赖;
package.json
{
"name": "blog_like",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"mongodb": "^3.6.2"
}
}
然后编辑mongo.js,在其中实现处理数据库的逻辑:
mongo.js
const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://<username>:<password>@<cluster_url><dbname>?retryWrites=true&w=majority";
async function getDocumentLike(docName) {
const client = new MongoClient(uri, { useNewUrlParser: true });
await client.connect();
const cmd = client.db('blog').collection('doc_like');
res = await cmd.findOne({"docName": docName});
if (res == null) {
res = addDocumentLike(docName, 0);
}
client.close();
return res;
}
async function addDocumentLike(docName, num) {
const client = new MongoClient(uri, { useNewUrlParser: true });
await client.connect();
const cmd = client.db('blog').collection('doc_like');
docObj = await cmd.findOne({"docName": docName});
if (docObj == null) {
docObj = {
"docName": docName,
"likeNum": 0
};
} else {
docObj.likeNum += num;
}
cmd.updateOne(
{"docName": docName},
{$set: docObj},
{"upsert": true},
function(err, res) {
if (err) {
throw err;
}
// console.log("1 document updated, res: " + res);
}
)
client.close()
return docObj
}
async function test(){
var res1 = await getDocumentLike("Algorithm");
console.log(res1);
var res2 = await addDocumentLike("Algorithm", 1);
console.log(res2);
}
test();
// module.exports = {getDocumentLike, addDocumentLike}
上面的uri规定了mongodb对应的连接地址;
而getDocumentLike
根据传入的文章名称,去寻找文章对应的点赞个数,如果未找到则说明数据库还没有这条数据,此时插入这条数据;
addDocumentLike
用于增加或者插入一条文章记录:首先取到当前文章点赞数,若不存在则插入一条新的文章记录,然后根据num设置点赞增加的个数,num可以是:
- 0:新增记录;
- 1:增加;
- -1:取消;
最后,先创建一个test函数,测试上面的函数没问题;
使用下面的命令测试:
node mongo.js
{ _id: 5f918523bc86842926379ae5, docName: 'Algorithm', likeNum: 3 }
{ _id: 5f918523bc86842926379ae5, docName: 'Algorithm', likeNum: 4 }
测试成功后,将test注释,并使用module.exports
暴露函数即可;
最后在index.js中使用暴露的函数处理接口逻辑:
index.js
'use strict';
var {getDocumentLike, addDocumentLike} = require('./mongo')
exports.main_handler = async (event, context) => {
var body = event.body;
var jsonObj = JSON.parse(body);
var resObj = {};
var actionId = jsonObj.actionId;
var docName = jsonObj.docName;
if (actionId == 'get') {
resObj = await getDocumentLike(docName);
} else if (actionId == 'add') {
resObj = await addDocumentLike(docName, 1);
} else if (actionId == 'subtract') {
resObj = await addDocumentLike(docName, -1);
}
return resObj;
};
接口采用POST请求,包括了actionId和docName两个参数:
- actionId用于判断点赞逻辑;
- docName用于处理对应的文章;
至此,整个简单的云函数开发完毕;
④ 上传代码
将上述三个文件上传:
选择提交方式为本地上传文件夹,上传包括上述三个文件的文件夹,最后点击保存即可上传:
上传后如果没有安装依赖,可以在下方选择在线安装依赖,并保存后即可安装依赖;
⑤ 配置触发器
选择左侧的触发管理,并创建一个API网关触发器,并选择请求方式为POST:
触发器创建完成后,即可处理API的POST请求;
可以在触发管理中获取到API的访问路径!
⑥ 测试
最后我们使用控制台进行函数测试(也可以使用POSTMAN根据上面获取到的API路径进行测试);
返回函数管理中,在下方的测试事件中选择Api Gateway 事件模板,并填写相应的参数进行测试:
以我的一个记录为例,可见成功被执行了!
前端展示
前端部分参考了这个博客中的实现:Twitter 红心点赞 CSS3 动画按钮特效
我的博客是使用Hexo构建的(不过无论使用哪个方式构建都是类似的),在对应主题相加点赞的地方插入html片段即可,比如:
<div id="like-container" style="text-align: center">
<div class="like-feed">
<p>觉得本文不错就点个<span>♥</span>再走吧~</p>
<div class="like-img">
<div class="like-heart" id="like" rel="like"></div>
<div class="like-count" id="like-count"></div>
</div>
</div>
</div>
<style>
#like-container {
margin: 0 auto;
width: 100%;
}
....
</style>
对于点赞逻辑的处理,这里仁者见仁吧,不过基本上就是用户进来就请求get到点赞个数,然后当用户点赞或者取消点赞之后,就请求上面的add或者subtract就行了!
① 前端请求
这里需要注意的是:
大家尽量使用Promise的风格进行ajax调用,反正我之前用的是ajax+callback这种success回调的方式;
呃……,有点问题;
② 跨域问题
既然牵扯到了API调用,那么另外一个不得不提的问题就是:跨域;
通常跨域问题可以通过jsonp等方式、配合后端解决;
不过既然你已经使用了serverless并配置了API触发器,为什么不直接在控制台管理这些呢?
腾讯云已经提供了API管理,在API网关中:
https://console.cloud.tencent.com/apigateway/
选择你绑定了云函数的服务名称,点击名称进入并勾选支持CORS:
完成后点击发布即可;
具体文章可以参考:
其他
接口可靠性
其实对于这种点赞功能的需求,可靠性不是那么重要,多一个少一个也是并不是完全不可接受的事情;
其次,由于免费的mongodb是在海外并且的,所以在查询延时等方面其实问题还是挺严重的;
这个可以通过提高云函数的超时时间来避免调用超时;
对于我的博客来说,由于部署服务器在加州,所以在选择mongodb的时候,尽量选择靠近的区域;
附录
- serverless后台:serverless_blog_like
- 前端样式:Twitter红心点赞CSS3动画按钮特效