云开发 For Web:一站式开发下一代 Serverless Web 应用

近两年来,Serverless 无疑是前端圈里最火热的话题之一,在各类技术峰会、各类技术文章里都能看到它的身影。若是你是一名前端开发者,必定很奇怪:html

“咱们这些前端切图仔,为何要关注 Serverless 这种云计算的概念?”前端

咱们就从这个话题开始聊起吧。node

为何前端开发者要关注 Serverless ?

这个问题用一句话回答就是:react

“Serverless 解放了端开发者(不只仅是 Web 开发者)的生产力,让端开发者能够更快、更好、更灵活地开发各类端上应用,不须要投入太多精力关注于后端服务的实现。”git

下面咱们就来慢慢解释这句话。github

在前端的史前时代,那个时候甚至尚未”前端工程师“这个职位分类,全部人都是后台开发,全部的网页和 Web 应用都是来自于后台渲染,CGI、PHP (甚至你可能都没据说过的 Perl)即是当时 Web 技术的代名词,那个时候的 JS 和 CSS,不过是“切图仔”在网页里写动效和弹窗的小玩具而已。web

后来,AJAX 技术出现了,最先在 Outlook Web Access 中出现,随后随着 Google Map、Gmail 等大型 Web 应用的实践,逐步为人所知。这项技术让页面内的 JS 也能异步地向服务器发起各类请求,而且把数据渲染到页面上。这个时候,前端工程师们开始接管视图层逻辑:数据库

image

再后来,Node.js 诞生,大大下降了前端开发者开发一个后台服务的难度,这也让前端开发者逐渐接管了接管了渲染逻辑,在这期间,各大前端框架(表明性的 React、Vue)的服务器端渲染也逐步成熟。npm

image

既然能用 Node.js 来作服务端渲染,那么拿 Node.js 来写后台业务逻辑、实现各类 HTTP API 固然也不在话下,因此在一些公司里,前端接管业务逻辑,后台只负责各类底层微服务的架构就出现了,这也是目前不少大公司在实行的架构:小程序

image

细心的你可能已经注意到了,在这个时候,渲染、HTTP API、后台业务逻辑这些东西,从端的角度看是属于服务端的,可是从分工角度看却属于前端开发的范畴,这就是 BFF(Backend for Frontend)的概念,它的优点在于:

  • 把核心业务逻辑彻底交给前端工程师,让业务逻辑能够更加灵活快速地变动;
  • 让后端工程师能够更加关注于海量服务的稳定性和可靠性,提高服务质量。

这就是为何大公司的不少业务,都开始愈来愈多地招 Node.js 全栈工程师的缘由。

可是 BFF 并非银弹,它仍是有必定问题的,好比在国内通晓先后端开发的全栈工程师太少,很难撑起大致量的业务开发。并且国内大多数前端工程师缺乏服务端开发的经验,让他们运维上百台服务器和一整套海量服务,有点强人所难:

  • 每一个服务器实例应该有多少核?多少内存?
  • 怎么优化 Linux 网络栈的各类参数?
  • 服务器宕机怎么办?双活、多活、同城、异地怎么搞?

而 Serverless 正是帮助前端工程师解决运维开发 BFF 的良药。

Serverless 这个单词,直译成中文的话,应该是“无服务器”。固然,这里的“无服务器”绝对不是说不须要任何服务器资源了,而是说不须要关心服务器的具体运维和管理,只须要写代码而后发布便可。

它包含了 FaaS(函数即服务)和 BaaS(后端即服务)两大块功能,把各类基础设施进行了抽象,即便不熟悉后端的开发者,也能快速高质量地开发出海量、稳定的后端服务,而这对于前端工程师维护 BFF 服务来讲,几乎是量身定作的。

enter image description here

举一个最简单的例子,你如今须要上线一个新的 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,让各个端的开发者可以基于这些能力,快速、优质地开发出功能丰富的应用。

image

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);

HTTP 访问

你也许会以为 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...

在云函数内部使用服务端 SDK

在 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 访问。传统的流程是下面这样的:

  1. 前端应用调用上传接口;
  2. 后台接收文件,把文件放置到文件存储服务内(例如 腾讯云 COS);
  3. 若是须要 CDN 加速文件访问,须要为 CDN 设置回源路径到后端 COS 上。

但若是使用云开发,只须要在客户端调用 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...

总结

上面的能力是否是有些让你看花眼了,彻底不知道要怎么搭配起来使用?

其实一张图就能够解决:

image

图中的客户端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 开发者带来效率和质量上的提高,帮助他们开发更多更优质的应用,免去运维、后台开发的烦恼,是云开发不变的愿景。虽然咱们目前已经有了不少强大又方便使用的能力,但这远不是咱们的终点(实际上咱们才刚刚起步),在将来咱们将会持续完善下面的能力,进一步完善云开发的体系:

  • 更多的支持平台
  • 更完整的用户登陆鉴权体系
  • 对 Vue、React 等主流框架的深度集成
  • 对 Vue、React SSR 的一站式支持
  • 更好的开发者工具、CLI、脚手架
  • 更增强大的日志、监控告警能力

PS:若是你以为这篇文章对你有帮助,不妨花几分钟时间,来试一试快速开始吧。

相关文章
相关标签/搜索