微信小程序云開發(fā)云函數(shù)

2022-05-12 16:00 更新

云函數(shù)即在云端(服務(wù)器端)運行的函數(shù)。在物理設(shè)計上,一個云函數(shù)可由多個文件組成,占用一定量的 CPU 內(nèi)存等計算資源;各云函數(shù)完全獨立;可分別部署在不同的地區(qū)。開發(fā)者無需購買、搭建服務(wù)器,只需編寫函數(shù)代碼并部署到云端即可在小程序端調(diào)用,同時云函數(shù)之間也可互相調(diào)用。

一個云函數(shù)的寫法與一個在本地定義的 JavaScript 方法無異,代碼運行在云端 Node.js 中。當(dāng)云函數(shù)被小程序端調(diào)用時,定義的代碼會被放在 Node.js 運行環(huán)境中執(zhí)行。我們可以如在 Node.js 環(huán)境中使用 JavaScript 一樣在云函數(shù)中進行網(wǎng)絡(luò)請求等操作,而且我們還可以通過云函數(shù)后端 SDK 搭配使用多種服務(wù),比如使用云函數(shù) SDK 中提供的數(shù)據(jù)庫和存儲 API 進行數(shù)據(jù)庫和存儲的操作,這部分可參考數(shù)據(jù)庫存儲后端 API 文檔。

云開發(fā)的云函數(shù)的獨特優(yōu)勢在于與微信登錄鑒權(quán)的無縫整合。當(dāng)小程序端調(diào)用云函數(shù)時,云函數(shù)的傳入?yún)?shù)中會被注入小程序端用戶的 openid,開發(fā)者無需校驗 openid 的正確性因為微信已經(jīng)完成了這部分鑒權(quán),開發(fā)者可以直接使用該 openid。

接下來,我們將逐步學(xué)習(xí)以下內(nèi)容:

  • 我的第一個云函數(shù)
  • 獲取小程序用戶信息
  • 異步返回結(jié)果
  • 使用 wx-server-sdk
  • 在開發(fā)者工具中管理云函數(shù)
  • 測試、日志與監(jiān)控
  • 注意事項

我的第一個云函數(shù)

我們以定義一個將兩個數(shù)字相加的函數(shù)作為我們第一個云函數(shù)的示例。

在項目根目錄找到 project.config.json 文件,新增 cloudfunctionRoot 字段,指定本地已存在的目錄作為云函數(shù)的本地根目錄

示例:

{
   "cloudfunctionRoot": "./functions/"
}

project.config.json 的其他配置,詳見項目配置文件。

完成指定之后,云函數(shù)的根目錄的圖標(biāo)會變成 “云目錄圖標(biāo)”,云函數(shù)根目錄下的第一級目錄(云函數(shù)目錄)是與云函數(shù)名字相同的,如果對應(yīng)的線上環(huán)境存在該云函數(shù),則我們會用一個特殊的 “云圖標(biāo)” 標(biāo)明

接著,我們在云函數(shù)根目錄上右鍵,在右鍵菜單中,可以選擇創(chuàng)建一個新的 Node.js 云函數(shù),我們將該云函數(shù)命名為 add。開發(fā)者工具在本地創(chuàng)建出云函數(shù)目錄和入口 index.js 文件,同時在線上環(huán)境中創(chuàng)建出對應(yīng)的云函數(shù)。創(chuàng)建成功后,工具會提示是否立即本地安裝依賴,確定后工具會自動安裝 wx-server-sdk。我們可以看到類似如下的一個云函數(shù)模板:

const cloud = require('wx-server-sdk')
// 云函數(shù)入口函數(shù)
exports.main = async (event, context) => {

}

云函數(shù)的傳入?yún)?shù)有兩個,一個是 event 對象,一個是 context 對象。event 指的是觸發(fā)云函數(shù)的事件,當(dāng)小程序端調(diào)用云函數(shù)時,event 就是小程序端調(diào)用云函數(shù)時傳入的參數(shù),外加后端自動注入的小程序用戶的 openid 和小程序的 appid。context 對象包含了此處調(diào)用的調(diào)用信息和運行狀態(tài),可以用它來了解服務(wù)運行的情況。在模板中也默認 require 了 wx-server-sdk,這是一個幫助我們在云函數(shù)中操作數(shù)據(jù)庫、存儲以及調(diào)用其他云函數(shù)的微信提供的庫,關(guān)于 wx-server-sdk 的使用我們在另一個章節(jié)講述。

我們填充一下模板:

exports.main = async (event, context) => {
  return {
    sum: event.a + event.b
  }
}

本段代碼的意思是將傳入的 a 和 b 相加并作為 sum 字段返回給調(diào)用端。

在小程序中調(diào)用這個云函數(shù)前,我們還需要先將該云函數(shù)部署到云端。在云函數(shù)目錄上右鍵,在右鍵菜單中,我們可以將云函數(shù)整體打包上傳并部署到線上環(huán)境中。

部署完成后,我們可以在小程序中調(diào)用該云函數(shù):

wx.cloud.callFunction({
  // 云函數(shù)名稱
  name: 'add',
  // 傳給云函數(shù)的參數(shù)
  data: {
    a: 1,
    b: 2,
  },
  success: function(res) {
    console.log(res.result) // 3
  },
  fail: console.error
})

當(dāng)然,Promise 風(fēng)格的調(diào)用也是支持的:

wx.cloud.callFunction({
  // 云函數(shù)名稱
  name: 'add',
  // 傳給云函數(shù)的參數(shù)
  data: {
    a: 1,
    b: 2,
  },
})
.then(res => {
  console.log(res.result) // 3
})
.catch(console.error)

那么到這里,我們就成功創(chuàng)建了我們的第一個云函數(shù),并在小程序中成功調(diào)用!

接下來,我們介紹云函數(shù)和小程序登錄態(tài)如何無縫結(jié)合,以及如何在云函數(shù)端獲取小程序用戶信息(openid 和 appid)。


獲取小程序用戶信息

云開發(fā)的云函數(shù)的獨特優(yōu)勢在于與微信登錄鑒權(quán)的無縫整合。當(dāng)小程序端調(diào)用云函數(shù)時,云函數(shù)的傳入?yún)?shù)中會被注入小程序端用戶的 openid,開發(fā)者無需校驗 openid 的正確性,因為微信已經(jīng)完成了這部分鑒權(quán),開發(fā)者可以直接使用該 openid。與 openid 一起同時注入云函數(shù)的還有小程序的 appid。

從小程序端調(diào)用云函數(shù)時,開發(fā)者可以在云函數(shù)內(nèi)使用 wx-server-sdk 提供的 getWXContext 方法獲取到每次調(diào)用的上下文(appid、openid等),無需維護復(fù)雜的鑒權(quán)機制,即可獲取天然可信任的用戶登錄態(tài)(openid)??梢詫戇@么一個云函數(shù)進行測試:

// index.js
const cloud = require('wx-server-sdk')
exports.main = (event, context) => {
  // 這里獲取到的 openId、 appId 和 unionId 是可信的,注意 unionId 僅在滿足 unionId 獲取條件時返回
  let { OPENID, APPID, UNIONID } = cloud.getWXContext() 

  return {
    OPENID,
    APPID,
    UNIONID,
  }
}

假設(shè)云函數(shù)命名為 test,上傳并部署該云函數(shù)后,可在小程序中測試調(diào)用:

wx.cloud.callFunction({
  name: 'test',
  complete: res => {
    console.log('callFunction test result: ', res)
  }
})

會在調(diào)試器看到輸出的 res 為如下結(jié)構(gòu)的對象:

{
  "APPID": "xxx",
  "OPENID": "yyy",
  "UNIONID": "zzz", // 僅在滿足 unionId 獲取條件時返回
}

接下來,我們一起看看如果在云函數(shù)中需要進行一段異步操作再返回的時候該如何處理。


異步返回結(jié)果

經(jīng)常,我們需要在云函數(shù)中處理一些異步操作,在異步操作完成后再返回結(jié)果給到調(diào)用方。此時我們可以通過在云函數(shù)中返回一個 Promise 的方法來完成。

一個最簡的 setTimeout 示例:

// index.js
exports.main = async (event, context) => {
  return new Promise((resolve, reject) => {
    // 在 3 秒后返回結(jié)果給調(diào)用方(小程序 / 其他云函數(shù))
    setTimeout(() => {
      resolve(event.a + event.b)
    }, 3000)
  })
}

假設(shè)云函數(shù)名字為 test,上傳部署該云函數(shù)后,我們可以在小程序端測試調(diào)用:

// 在小程序代碼中:
wx.cloud.callFunction({
  name: 'test',
  data: {
    a: 1,
    b: 2,
  },
  complete: res => {
    console.log('callFunction test result: ', res)
  },
})

此時應(yīng)該看到調(diào)試器輸出:

callFunction test result: 3

使用 npm

在云函數(shù)中我們可以引入第三方依賴來幫助我們更快的開發(fā)。云函數(shù)的運行環(huán)境是 Node.js,因此我們可以使用 npm 安裝第三方依賴。比如除了使用 Node.js 提供的原生 http 接口在云函數(shù)中發(fā)起網(wǎng)絡(luò)請求,我們還可以使用一個流行的 Node.js 網(wǎng)絡(luò)請求庫 request 來更便捷的發(fā)起網(wǎng)絡(luò)請求。

注意,現(xiàn)在上傳云函數(shù)時不會在云端自動安裝依賴,需要開發(fā)者在本地安裝好依賴后一起打包上傳。

接下來,我們一起了解下官方提供的云函數(shù)端 SDK: wx-server-sdk。


在云函數(shù)中使用 wx-server-sdk

云函數(shù)屬于管理端,在云函數(shù)中運行的代碼擁有不受限的數(shù)據(jù)庫讀寫權(quán)限和云文件讀寫權(quán)限。需特別注意,云函數(shù)運行環(huán)境即是管理端,與云函數(shù)中的傳入的 openId 對應(yīng)的微信用戶是否是小程序的管理員 / 開發(fā)者無關(guān)。

云函數(shù)中使用 wx-server-sdk 需在對應(yīng)云函數(shù)目錄下安裝 wx-server-sdk 依賴,在創(chuàng)建云函數(shù)時會在云函數(shù)目錄下默認新建一個 package.json 并提示用戶是否立即本地安裝依賴。請注意云函數(shù)的運行環(huán)境是 Node.js,因此在本地安裝依賴時務(wù)必保證已安裝 Node.js,同時 node 和 npm 都在環(huán)境變量中。如不本地安裝依賴,可以用命令行在該目錄下運行:

npm install --save wx-server-sdk@latest

在云函數(shù)中調(diào)用其他 API 前,同小程序端一樣,也需要執(zhí)行一次初始化方法:

const cloud = require('wx-server-sdk')
// 默認配置
cloud.init()
// 或者傳入自定義配置
cloud.init({
  env: 'some-env-id'
})

wx-server-sdk 與小程序端的云 API 以同樣的風(fēng)格提供了數(shù)據(jù)庫、存儲和云函數(shù)的 API。下面提供幾個簡單的操作數(shù)據(jù)庫、存儲和云函數(shù)的示例:

云函數(shù)中調(diào)用數(shù)據(jù)庫

假設(shè)在數(shù)據(jù)庫中已有一個 todos 集合,我們可以如下方式取得 todos 集合的數(shù)據(jù):

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async (event, context) => {
  // collection 上的 get 方法會返回一個 Promise,因此云函數(shù)會在數(shù)據(jù)庫異步取完數(shù)據(jù)后返回結(jié)果
  return db.collection('todos').get()
}

云函數(shù)中調(diào)用存儲

假設(shè)我們要上傳在云函數(shù)目錄中包含的一個圖片文件(demo.jpg):

const cloud = require('wx-server-sdk')
const fs = require('fs')
const path = require('path')

exports.main = async (event, context) => {
  const fileStream = fs.createReadStream(path.join(__dirname, 'demo.jpg'))
  return await cloud.uploadFile({
    cloudPath: 'demo.jpg',
    fileContent: fileStream,
  })
}
在云函數(shù)中,__dirname 的值是云端云函數(shù)代碼所在目錄

云函數(shù)中調(diào)用其他云函數(shù)

假設(shè)我們要在云函數(shù)中調(diào)用另一個云函數(shù) sum 并返回 sum 所返回的結(jié)果:

const cloud = require('wx-server-sdk')

exports.main = async (event, context) => {
  return await cloud.callFunction({
    name: 'sum',
    data: {
      x: 1,
      y: 2,
    }
  })
}

更詳細的 wx-server-sdk 文檔可參見服務(wù)端 API 文檔。

接下來,我們一起了解下云函數(shù)的運行機制。


運行機制

運行環(huán)境

云函數(shù)運行在云端 Linux 環(huán)境1中,一個云函數(shù)在處理并發(fā)請求的時候會創(chuàng)建多個云函數(shù)實例,每個云函數(shù)實例之間相互隔離,沒有公用的內(nèi)存或硬盤空間。云函數(shù)實例的創(chuàng)建、管理、銷毀等操作由平臺自動完成。每個云函數(shù)實例都在 /tmp 目錄下提供了一塊 512MB 的臨時磁盤空間用于處理單次云函數(shù)執(zhí)行過程中的臨時文件讀寫需求,需特別注意的是,這塊臨時磁盤空間在函數(shù)執(zhí)行完畢后可能被銷毀,不應(yīng)依賴和假設(shè)在磁盤空間存儲的臨時文件會一直存在。如果需要持久化的存儲,請使用云存儲功能。

無狀態(tài)函數(shù)

云函數(shù)應(yīng)是無狀態(tài)的,冪等的,即一次云函數(shù)的執(zhí)行不依賴上一次云函數(shù)執(zhí)行過程中在運行環(huán)境中殘留的信息。

為了保證負載均衡,云函數(shù)平臺會根據(jù)當(dāng)前負載情況控制云函數(shù)實例的數(shù)量,并且會在一些情況下重用云函數(shù)實例,這使得連續(xù)兩次云函數(shù)調(diào)用如果都由同一個云函數(shù)實例運行,那么兩者會共享同一個臨時磁盤空間,但因為云函數(shù)實例隨時可能被銷毀,并且連續(xù)的請求不一定會落在同一個實例,因此云函數(shù)不應(yīng)依賴之前云函數(shù)調(diào)用中在臨時磁盤空間遺留的數(shù)據(jù)??偟脑瓌t即是云函數(shù)代碼應(yīng)是無狀態(tài)的。

事件模型

云函數(shù)的調(diào)用采用事件觸發(fā)模型,小程序端的每一次調(diào)用即觸發(fā)了一次云函數(shù)調(diào)用事件,云函數(shù)平臺會新建或復(fù)用已有的云函數(shù)實例來處理這次調(diào)用。同理,因為云函數(shù)間也可以相互調(diào)用,因此云函數(shù)間相互調(diào)用也是觸發(fā)了一次調(diào)用事件。

自動擴縮容

開發(fā)者無需關(guān)心云函數(shù)擴容和縮容的問題,平臺會根據(jù)負載自動進行擴縮容。

Footnotes

  1. 當(dāng)前運行環(huán)境是在 CentOS 7.2 中,特別注意編寫代碼不應(yīng)依賴特定的操作系統(tǒng)或特定的操作系統(tǒng)版本號,運行環(huán)境可能會發(fā)生變化,代碼應(yīng)盡量與平臺無關(guān)

注意事項 & FAQ

臨時存儲空間

云函數(shù)的運行環(huán)境中在 /tmp 目錄下提供了一塊 512MB 的臨時磁盤空間,用于處理單次云函數(shù)執(zhí)行過程中的臨時文件讀寫需求,需特別注意的是,這塊臨時磁盤空間在函數(shù)執(zhí)行完畢后可能被銷毀,不應(yīng)依賴和假設(shè)在磁盤空間存儲的臨時文件會一直存在。如果需要持久化的存儲,請使用云存儲功能。

用戶代碼目錄:__dirname

在云函數(shù)執(zhí)行過程中,通過 __dirname 可獲取當(dāng)前云函數(shù)的根目錄,如果有隨云函數(shù)打包上傳的資源文件,可以通過 __dirname 加相對路徑引用獲取。

Node.js native 依賴

如果有使用到平臺相關(guān)的 native 依賴,即依賴需要在相應(yīng)平臺下編譯(Windows / macOS / Linux ...)的,務(wù)必注意在 Linux 平臺(CentOS 7 最佳)下編譯后再上傳,否則可能出現(xiàn)環(huán)境兼容性問題。


在開發(fā)者工具中管理云函數(shù)

配置云函數(shù)本地目錄

在項目根目錄中可以使用 project.config.json 文件,在其中定義 cloudfunctionRoot 字段,指定本地已存在的目錄作為云函數(shù)的本地根目錄。

云函數(shù)操作

在云函數(shù)根目錄或者云函數(shù)目錄上,通過鼠標(biāo)右鍵,我們可以喚出右鍵菜單,完成以下操作

  1. 查看當(dāng)前環(huán)境
  2. 切換環(huán)境
  3. 新建 Node.js 云函數(shù)
  4. 下載線上環(huán)境的云函數(shù)列表
  5. 下載線上環(huán)境的云函數(shù)代碼并覆蓋本地
  6. 對比本地代碼和線上環(huán)境的代碼
  7. 上傳并部署云函數(shù)到線上環(huán)境

查看和切換環(huán)境

在云函數(shù)根目錄上右鍵,在右鍵菜單中,可以查看當(dāng)前對應(yīng)的環(huán)境,同時可以切換環(huán)境,之后的所有右鍵菜單都是在這個環(huán)境下進行操作

新建 Node.js 云函數(shù)

在云函數(shù)根目錄上右鍵,在右鍵菜單中,可以選擇創(chuàng)建一個新的 Node.js 云函數(shù),開發(fā)者工具在本地創(chuàng)建出以下目錄和文件,同時在線上環(huán)境中創(chuàng)建出對應(yīng)的云函數(shù):

  • 云函數(shù)目錄:以云函數(shù)名字命名的目錄,存放該云函數(shù)的所有代碼
  • index.js:云函數(shù)入口文件,云函數(shù)被調(diào)用時實際執(zhí)行的入口函數(shù)是 index.js 中導(dǎo)出的 main 方法
  • package.json:npm 包定義文件,其中默認定義了最新 wx-server-sdk 依賴

在創(chuàng)建成功后,工具會提示是否為該云函數(shù)立即安裝本地依賴即 wx-server-sdk,如是,則工具會開啟終端執(zhí)行 npm install


下載云函數(shù)列表

在云函數(shù)根目錄上右鍵,在右鍵菜單中,我們可以將線上環(huán)境中的云函數(shù)列表同步到本地,開發(fā)者工具會根據(jù)云函數(shù)的名字,在本地中創(chuàng)建出對應(yīng)的云函數(shù)目錄

下載云函數(shù)

在一個云函數(shù)目錄上右鍵可以在菜單中選擇下載該云函數(shù),云函數(shù)代碼會被下載到指定目錄。

上傳并部署

在云函數(shù)目錄上右鍵,在右鍵菜單中,我們可以將云函數(shù)整體打包上傳并部署到線上環(huán)境中

更多設(shè)置

我們通過右鍵菜單的 “更多設(shè)置” 可以進入云函數(shù)的沉浸式交互場景,在這個場景里可以完成以上所有的云函數(shù)操作,在云目錄上按 ctrl 可以進行多選批量操作

接下來,我們一起看看如何在開發(fā)云函數(shù)時進行測試、查看日志、以及查看監(jiān)控。


測試、日志與監(jiān)控

測試

云開發(fā)提供了云函數(shù)測試功能,可以方便地調(diào)試你的代碼。在控制臺的對應(yīng)云函數(shù)的管理面板中,點擊 “測試” 按鈕即可打開測試彈窗。

測試彈窗

點擊“提交方法”下拉菜單可以選擇測試函數(shù)的模板方法,當(dāng)前只支持Hello World 事件模板。模板在測試時作為 event 參數(shù)傳遞給函數(shù)。在“測試參數(shù)”的編輯器中輸入想測試的參數(shù)后,點擊“執(zhí)行”按鈕即可運行代碼。執(zhí)行完畢后將在“運行測試”欄顯示運行結(jié)果。

除了可視化的云函數(shù)測試功能,我們還提供命令行工具 scf-cli, 助你在本地快速調(diào)試。

日志

在這里可以查看云函數(shù)的調(diào)用日志,方便開發(fā)者對開發(fā)調(diào)試。

監(jiān)控

在這里可以查看云函數(shù)的調(diào)用次數(shù)、運行時間、錯誤次數(shù)。并支持將這些數(shù)據(jù)導(dǎo)出。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號