近两年来,Serverless 无疑是前端圈里最火热的话题之一,在各类技术峰会、各类技术文章里都能看到它的身影。若是你是一名前端开发者,必定很奇怪:html
“咱们这些前端切图仔,为何要关注 Serverless 这种云计算的概念?”前端
咱们就从这个话题开始聊起吧。node
这个问题用一句话回答就是:react
“Serverless 解放了端开发者(不只仅是 Web 开发者)的生产力,让端开发者能够更快、更好、更灵活地开发各类端上应用,不须要投入太多精力关注于后端服务的实现。”git
下面咱们就来慢慢解释这句话。github
在前端的史前时代,那个时候甚至尚未”前端工程师“这个职位分类,全部人都是后台开发,全部的网页和 Web 应用都是来自于后台渲染,CGI、PHP (甚至你可能都没据说过的 Perl)即是当时 Web 技术的代名词,那个时候的 JS 和 CSS,不过是“切图仔”在网页里写动效和弹窗的小玩具而已。web
后来,AJAX 技术出现了,最先在 Outlook Web Access 中出现,随后随着 Google Map、Gmail 等大型 Web 应用的实践,逐步为人所知。这项技术让页面内的 JS 也能异步地向服务器发起各类请求,而且把数据渲染到页面上。这个时候,前端工程师们开始接管视图层逻辑:数据库
再后来,Node.js 诞生,大大下降了前端开发者开发一个后台服务的难度,这也让前端开发者逐渐接管了接管了渲染逻辑,在这期间,各大前端框架(表明性的 React、Vue)的服务器端渲染也逐步成熟。npm
既然能用 Node.js 来作服务端渲染,那么拿 Node.js 来写后台业务逻辑、实现各类 HTTP API 固然也不在话下,因此在一些公司里,前端接管业务逻辑,后台只负责各类底层微服务的架构就出现了,这也是目前不少大公司在实行的架构:小程序
细心的你可能已经注意到了,在这个时候,渲染、HTTP API、后台业务逻辑这些东西,从端的角度看是属于服务端的,可是从分工角度看却属于前端开发的范畴,这就是 BFF(Backend for Frontend)的概念,它的优点在于:
这就是为何大公司的不少业务,都开始愈来愈多地招 Node.js 全栈工程师的缘由。
可是 BFF 并非银弹,它仍是有必定问题的,好比在国内通晓先后端开发的全栈工程师太少,很难撑起大致量的业务开发。并且国内大多数前端工程师缺乏服务端开发的经验,让他们运维上百台服务器和一整套海量服务,有点强人所难:
而 Serverless 正是帮助前端工程师解决运维开发 BFF 的良药。
Serverless 这个单词,直译成中文的话,应该是“无服务器”。固然,这里的“无服务器”绝对不是说不须要任何服务器资源了,而是说不须要关心服务器的具体运维和管理,只须要写代码而后发布便可。
它包含了 FaaS(函数即服务)和 BaaS(后端即服务)两大块功能,把各类基础设施进行了抽象,即便不熟悉后端的开发者,也能快速高质量地开发出海量、稳定的后端服务,而这对于前端工程师维护 BFF 服务来讲,几乎是量身定作的。
举一个最简单的例子,你如今须要上线一个新的 HTTP API(好比 /getUser?id=123
),若是使用 Serverless 服务的话,有多快呢?
你只须要写下面这个云函数:
module.exports = async function(events, context) { const { id } = events.query.id const userInfo = await fetchUserInfo(id) // 调用后端微服务,拉取用户信息 return userInfo }
而后发布这个云函数(假设命名为 getUser
),而且为它设置一条路由:
cloudbase service:create -f getUser -p /getUser
而后你就能够经过 https://xxx.com/getUser
来拉取数据了,同时还附赠海量弹性伸缩、异地多活、日志监控等多方位的能力。
若是你以为这样很酷炫,那么不如来试一试 云开发 Cloudbase 吧!
云开发(Cloudbase)是腾讯云 TCB 团队(Tencent Cloudbase)出品的云端一体化产品方案,为广大的小程序、Web、移动端开发者提供一站式的 Serverless 服务。
固然这是官方的说法,用人话讲就是:
用了云开发,各个端的开发者就能够一站式地解决后端服务问题了!
实际上早在 2018 年,云开发就联合微信团队推出了「小程序·云开发」,若是你对它还不怎么了解,能够看这两篇文章:
而如今,云开发 For Web 也正式上线了!
云开发提供了云数据库、云函数、云存储、用户登陆体系等一系列的后端能力,而且提供了各端的 SDK,让各个端的开发者可以基于这些能力,快速、优质地开发出功能丰富的应用。
Talk is cheap, Show me the code!
口说无凭,咱们仍是来直接看代码吧!
云开发提供了一个文档型的 NoSQL 数据库,与传统的云上数据库不一样的是,云开发的数据库能够在各类客户端内使用 SDK 直接进行读写,好比 Web 应用、小程序内、Flutter 客户端等等。
下面咱们以 Web 应用为例,展现云数据库的一系列功能。
CURD是数据库最基础的功能,云开发 SDK 提供了一套链式调用接口,对数据库进行读写:
// 使用 Web 端 SDK const cloudbase = require('tcb-js-sdk') const app = cloudbase.init({ /* 初始化... */ }) const db = app.database() // 插入文档 await db.collection('messages').add({ author: 'stark', message: 'Hello World!' }) // 查询文档 const data = await db.collection('messages').where({ author: 'stark' }).get() // 更新文档 await db.collection('messages').where({ author: 'stark' }).update({ message: 'Hi, Cloudbase!' }) // 删除文档 await db.collection('messages').where({ author: 'stark' }).remove()
普通的查询可能没法知足一些复杂的需求,好比联表、group等等。
云开发针对这些复杂的查询场景,推出了聚合搜索的功能,把一系列操做抽象为一个管道(pipeline),单次执行便可,避免了屡次读的性能问题,咱们以 group 操做为例:
const $ = db.command.aggregate const result = await db .collection('message') .aggregate() .group({ // 以 author 字段做为 key,统计相同 author 的数量 _id: '$author' messagesCount: $.sum(1) }) .end() //=> { "_id": "stark", messagesCount: 12 }
更多的聚合搜索功能,能够参考:Aggregate | 云开发 Cloudbase
在订票、预定、转帐等等场景下,开发者可能会要求数据库可以保证一连串读写的原子性,避免出现竞争条件,这就是数据库事务的使用场景。
云开发数据库固然也提供了事务功能:
// 启动事务 const transaction = await db.startTransaction() // 在事务内读 const data = await transaction.collection('messages') .where({ /* <query> */}) .get() // 在事务内写 await transaction.collection('messages') .where({ /* <query> */}) .update({ /* <data> */}) // 提交事务 await transaction.commit()
在实时聊天室、实时数据看板等等场景下,咱们常常会须要订阅数据库的更新,从而实现实时数据推送。
云开发的数据库提供的 watch()
方法就是为此设计的,每当数据库符合条件的文档发生变化时,都会触发 onChange
回调,示例代码以下:
await db.collection('messages') .where({/* <query> */}) .watch({ onChange: snapshot => { console.log("收到snapshot!", snapshot) }, onError: error => { console.log("收到error!", error) } })
更多信息能够参考:数据库实时推送 | 云开发 Cloudbase
所谓的云函数,即是在云端运行的、事件驱动的一段代码,它能够被 SDK 调用,也能够直接经过 HTTP 调用,还能够设置定时器让它按期运行:
// sum.js module.exports = async function(events) { return events.a + events.b }
这一小段代码很简单,可是隐藏在它之下的倒是一整套庞大的 FaaS(函数即服务)基础设施,提供了诸如弹性伸缩、日志、监控告警等多方面的能力。
使用云开发的客户端 SDK,能够垂手可得地在各个端上调用云函数,咱们以 Web 应用为例:
const cloudbase = require("tcb-js-sdk"); const app = cloudbase.init({/* 初始化 */}); app.callFunction({ // 云函数名称 name: "sum", // 传给云函数的参数 data: { a: 1, b: 2 } }) .then(res => { console.log(res); // 输出 "3" }) .catch(error);
你也许会以为 SDK 体积庞大,太沉重了,那么你也能够选择使用 HTTP 来调用云函数,响应 HTTP 请求。
// hello.js module.exports = function() { return 'Hello, World!' }
而后咱们直接经过命令行发布这个函数,并为它建立一条路由:
$ cloudbase functions:deploy hello $ cloudbase service:create -f hello -p /hello
随后即可以经过 url 直接访问这个云函数:
$ curl https://xxx.service.tcloudbase.com/hello Hello, World!
具体能够参考:https://docs.cloudbase.net/se...
在 Cloudbase 的云函数内,你能够直接使用 Node.js SDK,无需在初始化的时候额外注入秘钥:
const cloudbase = require('@cloudbase/node-sdk') // 无需使用服务端秘钥 const app = cloudbase.init() const data = await app.database().where().get()
更详细的内容能够参考:https://docs.cloudbase.net/ap...
咱们在开发应用的过程当中,常常会遇到图片、文件上传的需求,而且可能须要为这些文件设置 CDN 访问。传统的流程是下面这样的:
但若是使用云开发,只须要在客户端调用 uploadFile
,就能够一步完成上面的三件事情:
const tcb = require("tcb-js-sdk"); const app = tcb.init({ env: 'your-env-id' }) const { fileID } = await app.uploadFile({ // 云端路径 cloudPath: "/a/b/c/filename", // 须要上传的文件,File 类型 filePath: document.getElementById('file').files[0] })
uploadFile
会返回一个 fileID
,是云开发内文件的惟一标识符,咱们可使用 getTempFileURL
来获取文件 URL 访问连接:
const tcb = require("tcb-js-sdk"); const app = tcb.init({ env: 'your-env-id' }) const { fileList } = app.getTempFileURL({ fileList: [ 'cloud://a/b/c' ] }) // fileList 是一个有以下结构的对象数组 // [{ // fileID: 'cloud://a/b/c', // 文件 ID // tempFileURL: 'http://xxx/xxx/xxx', // 临时文件网络连接 // maxAge: 120 * 60 * 1000, // 有效期 // }]
更详细的内容,能够参考:https://docs.cloudbase.net/st...
云开发除了上述的基础功能以外,还提供了一系列的扩展能力,包括但不只限于:
更详细的内容,能够参考:https://docs.cloudbase.net/ex...
上面的能力是否是有些让你看花眼了,彻底不知道要怎么搭配起来使用?
其实一张图就能够解决:
图中的客户端SDK包括:
服务端 SDK 包括:
光看示例代码固然没有什么意思,咱们接下来就拿云开发的一些能力,来快速开发一个实时在线聊天室吧。
项目代码:https://github.com/TencentClo...
这是一个由 create-react-app
快速生成的脚手架项目,因此大部分构建和工程化的细节这里就略过不谈了,咱们直接来看代码实现,大体上实现了三个功能,括号中是使用的云开发能力:
首先是咱们的初始化流程,先使用匿名登陆,而后创建实时数据推送的链接:
async function init() { // 使用匿名登陆 await auth.anonymousAuthProvider().signIn(); // 使用 refreshToken 的前 6 位做为 uid setUid(auth.hasLoginState().credential.refreshToken.slice(0, 6)); // 创建实时数据推送链接 await db .collection("messages") .where({}) .watch({ onChange(snapshot) { setList(snapshot.docs); setLoading(false); }, onError(err) { console.log(err); }, }); }
创建实时链接以后,集合中的任何变化,都会触发 onChange()
回调,而后咱们使用 setList()
来更新界面上的消息数据。
固然只读消息是不够的,咱们还须要发送消息,具体实现很是简单,能够看 sendMessage()
方法,直接使用 add()
方法向数据库写入数据就能够了:
// 发送消息 async function sendMessage() { const message = { timestamp: new Date().getTime(), text, uid, }; await db.collection("test").add(message); // 清空输入栏 setText(""); }
固然以上只是局部的代码片断,总体代码能够参考:
https://github.com/TencentClo...
开发完毕以后,咱们即可以使用 云开发静态网站 来托管咱们的这个聊天室 Web 应用。
首先咱们构建咱们的应用:
$ npm run build
构建产物会生成到 build
目录下。
而后咱们发布到静态托管便可(托管前,请先开通静态网站):
$ cloudbase hosting:deploy ./build -e your-env-id
发布完成后,你即可以经过 https://xxxx.tcb.qcloud.la/xxxx
的来访问你的应用了。进一步,你还能够为它绑定自定义域名。
PS:实际上,云开发的主页和官方文档,就是这样托管的(毕竟作云服务的,最重要的就是 Eating your own dog food 嘛)。
固然,除了这个实战 Demo 之外,还能够看看一些真正业务的实践:
给 Web 开发者带来效率和质量上的提高,帮助他们开发更多更优质的应用,免去运维、后台开发的烦恼,是云开发不变的愿景。虽然咱们目前已经有了不少强大又方便使用的能力,但这远不是咱们的终点(实际上咱们才刚刚起步),在将来咱们将会持续完善下面的能力,进一步完善云开发的体系:
PS:若是你以为这篇文章对你有帮助,不妨花几分钟时间,来试一试快速开始吧。