雲開發 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:若是你以爲這篇文章對你有幫助,不妨花幾分鐘時間,來試一試快速開始吧。

相關文章
相關標籤/搜索