云開發(fā) 云開發(fā)能力

2020-07-20 11:22 更新

在上一節(jié),我們大致體驗(yàn)了一下云開發(fā):開通了云開發(fā)服務(wù),相當(dāng)于在云端擁有了一個(gè)Nodejs的環(huán)境,我們可以把云函數(shù)部署到云端。通過(guò)云開發(fā)的能力進(jìn)行調(diào)用云函數(shù)、上傳圖片、操作數(shù)據(jù)庫(kù)以及使用小程序的一些開放接口,下面來(lái)進(jìn)一步了解和使用云開發(fā)能力,并加強(qiáng)對(duì)云端測(cè)試、本地調(diào)試以及本地Console日志打印,云端日志打印的理解。

用編程來(lái)寫項(xiàng)目,就像是在做一系列精密而復(fù)雜的實(shí)驗(yàn),你不能總是勞煩他人幫你解決問(wèn)題,而是要掌握調(diào)試、測(cè)試、日志打印等手段來(lái)檢查每一步操作是否正確,你需要學(xué)會(huì)查看報(bào)錯(cuò)信息,如果不正確問(wèn)題在哪、出了什么問(wèn)題,你才能有針對(duì)性的去搜索,有針對(duì)性的去咨詢他人。

本地調(diào)試與云端測(cè)試

為了能夠讓大家更加清楚的了解:完整操作一個(gè)云函數(shù)的流程以及本地調(diào)試與云端測(cè)試的重要性,我們以長(zhǎng)方形的邊長(zhǎng)(a、b)求周長(zhǎng)、面積這個(gè)簡(jiǎn)單的數(shù)學(xué)公式為例。

第一步:新建云函數(shù)

首先我們右鍵點(diǎn)擊云函數(shù)根目錄(也就是cloudfunctions文件夾),選擇新建Nodejs云函數(shù),函數(shù)名為長(zhǎng)方形的英文rectangle,然后打開index.js,修改return里的內(nèi)容為如下:

exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  return {
    circum:(event.width+event.height)*2,
    area:event.width*event.height
  }
}

circum是周長(zhǎng),周長(zhǎng)=(寬度width+高度height)??2;area是面積,面積=寬度width??高度height,只要我們之后把長(zhǎng)方形的參數(shù)寬度width和高度height傳遞進(jìn)來(lái)(之后我們會(huì)來(lái)講怎么傳),即可獲得長(zhǎng)方形的周長(zhǎng)和面積。

建好云函數(shù)之后,我們右鍵點(diǎn)擊云函數(shù)目錄,也就是rectangle文件夾,選擇在終端中打開,使用npm install來(lái)安裝依賴。

npm install

第二步:本地調(diào)試云函數(shù)是否正確

對(duì)于一個(gè)復(fù)雜的云函數(shù),我們最好是先在本地測(cè)試一下云函數(shù)是否正確,然后再部署上傳到云端。那如何本地測(cè)試呢?右鍵點(diǎn)擊云函數(shù)目錄,也就是rectangle文件夾,選擇本地調(diào)試(這種方式進(jìn)入本地調(diào)試會(huì)默認(rèn)開啟rectangle的本地調(diào)試),修改以下代碼:

{
  "key": "value"
}

我們給參數(shù)寬度width和高度height賦值(注意傳遞的是JSON格式,最后一個(gè)參數(shù)結(jié)尾不能有逗號(hào),),比如賦值為3和6:

{
  "width": 3,
  "height":7
}

然后點(diǎn)擊調(diào)用,如果顯示函數(shù)執(zhí)行成功(注意仍然是在調(diào)試的console標(biāo)簽),并得到周長(zhǎng)circum和面積area的結(jié)果分別為20、21,那證明云函數(shù)沒有寫錯(cuò),這時(shí)候我們就可以部署并上傳到云端了。

第三步:云端測(cè)試云函數(shù)是否正確

打開云開發(fā)控制臺(tái)的云函數(shù)標(biāo)簽頁(yè),找到rectangle云函數(shù),點(diǎn)擊云端測(cè)試,同樣我們給參數(shù)賦值,將以下代碼進(jìn)行修改:

{
  "key1": "test value 1",
  "key2": "test value 2"
}

比如給寬度width賦值為4,高度height賦值為7,即代碼修改為:

{
  "width": 4,
  "height": 7
}

然后點(diǎn)擊運(yùn)行測(cè)試,(會(huì)等一段時(shí)間),再來(lái)查看測(cè)試的結(jié)果,如果返回結(jié)果如下,則表示在云端的云函數(shù)可以正常調(diào)用:

{"circum":22,"area":28}

在云端測(cè)試的調(diào)用結(jié)果也是可以在云開發(fā)控制臺(tái)云函數(shù)的日志里查看到的。

在第一節(jié)我們要觸發(fā)云函數(shù),需要在小程序頁(yè)面里寫一個(gè)組件(比如button)并綁定事件處理函數(shù),然后再在事件處理函數(shù)(或在頁(yè)面的生命周期函數(shù))里使用wx.cloud.callFunction()調(diào)用云函數(shù),通過(guò)這種方式來(lái)觸發(fā)云函數(shù),會(huì)比較麻煩,而本地調(diào)試和云端測(cè)試則可以直接觸發(fā)云函數(shù)查看結(jié)果,大大提升了調(diào)試的便利度。

云函數(shù)的調(diào)用采用事件觸發(fā)模型,小程序端的調(diào)用、本地調(diào)試和云端測(cè)試都會(huì)觸發(fā)云函數(shù)的調(diào)用事件,其中本地調(diào)試調(diào)用的不是云端的云函數(shù),而是小程序本地的云函數(shù)。

小任務(wù):rectangle云函數(shù)需要傳入兩個(gè)參數(shù)才能返回值,有些云函數(shù),比如前面的login云函數(shù)不需要傳入?yún)?shù),你知道應(yīng)該怎么進(jìn)行本地調(diào)試和云端測(cè)試嗎?在本地調(diào)試的請(qǐng)求方式有手動(dòng)觸發(fā)和模擬器觸發(fā),開啟模擬器觸發(fā),點(diǎn)擊第一節(jié)“點(diǎn)擊獲取openid”的按鈕試試看(注意這時(shí)調(diào)用的是本地的云函數(shù),修改一下login云函數(shù)不上傳試試看);

小程序端與服務(wù)端

小程序端與云端的初始化

小程序默認(rèn)可以創(chuàng)建兩個(gè)環(huán)境,這兩個(gè)環(huán)境都有云函數(shù)配置、數(shù)據(jù)庫(kù)、云存儲(chǔ)且獨(dú)立隔離,開發(fā)上會(huì)存在兩個(gè)環(huán)境切換的情況(一個(gè)用于生產(chǎn)環(huán)境,一個(gè)用于測(cè)試環(huán)境),而區(qū)別這兩個(gè)環(huán)境的就是它們的環(huán)境ID,小程序端與云端的初始化時(shí)要注意。

在前面我們介紹過(guò)小程序的初始化是在app.js文件里使用wx.cloud.init來(lái)初始化,如下:

wx.cloud.init({
  env: 'my-env-id', //可以填寫生產(chǎn)環(huán)境或者測(cè)試環(huán)境的環(huán)境ID
  traceUser: true,
})

這里的 env 只會(huì)決定小程序端API調(diào)用的云環(huán)境(如云函數(shù)、云存儲(chǔ)、數(shù)據(jù)庫(kù),畢竟有兩個(gè)環(huán)境里都有),并不會(huì)決定云函數(shù)中的 API 調(diào)用的環(huán)境。在開發(fā)者工具的控制臺(tái),也會(huì)打印默認(rèn)環(huán)境: 當(dāng)前代碼初始化的默認(rèn)環(huán)境為:你的默認(rèn)環(huán)境ID

當(dāng)前代碼初始化的默認(rèn)環(huán)境為:你的默認(rèn)環(huán)境ID

云函數(shù)中的API調(diào)用的環(huán)境也可以使用初始化來(lái)設(shè)置。

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})

cloud.DYNAMIC_CURRENT_ENV設(shè)置 API 默認(rèn)環(huán)境等于當(dāng)前所在環(huán)境。建議所有的云函數(shù)都使用以上方式來(lái)初始化,也就是配置env的值為cloud.DYNAMIC_CURRENT_ENV或使用你的環(huán)境ID,不要為空。

關(guān)于wx-server-sdk

每一個(gè)云函數(shù)都會(huì)用到wx-server-sdk這個(gè)Node包,而要使用這個(gè)包都需要有Nodejs環(huán)境,小程序端的本地需要我們自己下載Nodejs(前面已下載),而云端則自帶Nodejs環(huán)境。那這個(gè)wx-server-sdk到底什么呢?我們可以打開它的npm包地址:

npm包地址:wx-server-sdk包地址

在Dependencies標(biāo)簽頁(yè)可以看到wx-server-sdk依賴 tcb-admin-node、protobufjs、tslib這三個(gè)包,而其中tcb-admin-node是核心,學(xué)有余力的童鞋可以看一下它的技術(shù)文檔。

技術(shù)文檔:tcb-admin-node的Github地址

async與await

在wx-server-sdk中不再兼容success、fail、complete回調(diào),只會(huì)返回Promise。在云函數(shù)中也經(jīng)常會(huì)需要處理一些異步操作,在異步操作完成后再返回結(jié)果給到調(diào)用方,我們可以通過(guò)在云函數(shù)中返回一個(gè) Promise 的方法來(lái)實(shí)現(xiàn)。Promise表示異步操作返回的結(jié)果。在新建的云函數(shù)里會(huì)看到下面這樣的一個(gè)語(yǔ)句(有 async):

exports.main = async (event, context) => {
}

async表示函數(shù)里有異步操作,async函數(shù)的返回值是一個(gè) Promise 對(duì)象。在后面還會(huì)遇到 await,表示緊跟在它后面的表達(dá)式需要等待結(jié)果;以及promise對(duì)象的then()方法(有點(diǎn)類似于success回調(diào)函數(shù)),和catch()方法(有點(diǎn)類似于fail回調(diào)函數(shù)),這些我們以后會(huì)經(jīng)常遇到,先理解不了也沒有關(guān)系,大家在書寫時(shí)推薦云函數(shù)使用上面的寫法就對(duì)了。

云函數(shù)的注意事項(xiàng)


    在云函數(shù)部署并上傳到云端之后,更新里面的文件比如index.js、config.json,建議右鍵點(diǎn)擊更新好的文件(不是云函數(shù)目錄)選擇云函數(shù)增量上傳:更新文件,不建議通過(guò)上傳并部署所有文件的方式,否則在幾分鐘內(nèi)會(huì)出現(xiàn)云函數(shù)調(diào)用失敗的情況;
    刪除一個(gè)云函數(shù)之后,不建議再新建一個(gè)同名的云函數(shù)并上傳部署,否則在十多分鐘內(nèi)會(huì)出現(xiàn)云函數(shù)調(diào)用失敗的情況,建議換一個(gè)云函數(shù)名,比如login換成user,在小程序端使用 wx.cloud.callFunction({name: ''})調(diào)用云函數(shù)時(shí)把name的值換成user就可以了
    調(diào)用云函數(shù)時(shí),我們還可以在開發(fā)者工具調(diào)試面板的NetWork標(biāo)簽查看調(diào)用云函數(shù)的情況。

獲取用戶信息和登錄

在生命周期章節(jié),我們大致介紹了一下如何使用wx.getUserInfo API和通過(guò)組件的open-type=”getUserInfo” 來(lái)獲取用戶的信息(如頭像、昵稱),下面我們就來(lái)詳細(xì)介紹云開發(fā)的免鑒權(quán)登錄與用戶信息的結(jié)合。

使用open-type=”getUserInfo” 來(lái)獲取用戶信息的作用和 wx.getUserInfo API基本效果是一樣的,區(qū)別在于wx.getUserInfo 這種方式最好是在用戶允許獲取公開信息(也就是res.authSetting[‘scope.userInfo’]的值為true)之后再調(diào)用,如果用戶拒絕了授權(quán)就不會(huì)再有彈窗(除非用戶刪掉了你的小程序再使用),調(diào)用就會(huì)失敗,而使用組件的方式是用戶主動(dòng)點(diǎn)擊,用戶即使拒絕了,再點(diǎn)擊仍會(huì)彈出授權(quán)彈窗。所以推薦先使用組件來(lái)獲取用戶授權(quán),然后再來(lái)使用wx.getUserInfo來(lái)獲取用戶信息。

通過(guò)button獲取用戶信息

使用開發(fā)者工具新建一個(gè)login頁(yè)面,然后在login.wxml里輸入以下代碼,我們通過(guò)組件的方式來(lái)獲取用戶的信息:

<button open-type="getUserInfo" bindgetuserinfo="getUserInfomation">點(diǎn)擊獲取用戶信息</button>
<image src="{{avatarUrl}}"></image>
<view>{{city}}</view>
<view>{{nickName}}</view>

在login.js的data里初始化avatarUrl、nickName以及city,沒有獲取到用戶信息時(shí),用一張默認(rèn)圖片代替,昵稱顯示用戶未登錄,city顯示為未知:

  data: {
    avatarUrl: '/images/user-unlogin.png',
    nickName:"用戶未登陸",
    city:"未知",
  },

然后在login.js文件里輸入以下代碼,在事件處理函數(shù)getUserInfomation我們可以打印event對(duì)象,open-type=”getUserInfo”的組件的event對(duì)象的detail里就有userInfo:

  getUserInfomation: function (event) {
    console.log('getUserInfomation打印的事件對(duì)象', event)
    let { avatarUrl, city, nickName}= event.detail.userInfo
    this.setData({
      avatarUrl,city, nickName
    })
  },

將獲取的avatarUrl,city,nickName通過(guò)this.setData()賦值給data。編譯之后點(diǎn)擊點(diǎn)擊獲取用戶信息按鈕,首先會(huì)彈出授權(quán)彈窗,當(dāng)用戶確認(rèn)之后,就會(huì)顯示用戶的信息。

獲取用戶高清頭像

我們發(fā)現(xiàn)獲取到的頭像不是很清晰,這是因?yàn)槟J(rèn)的頭像大小為132132(UserInfo用戶頭像說(shuō)明),如果把a(bǔ)vatarUrl鏈接后面的132修改為0就能獲取到640640大小的頭像了:

  getUserInfomation: function (event) {
    let { avatarUrl, city, nickName}= event.detail.userInfo
    avatarUrl = avatarUrl.split("/")
    avatarUrl[avatarUrl.length - 1] = 0;
    avatarUrl = avatarUrl.join('/'); 
    this.setData({
      avatarUrl,city, nickName
    })
  },

頁(yè)面加載時(shí)就顯示用戶信息

在獲得了用戶授權(quán)和用戶信息的情況下,刷新頁(yè)面或進(jìn)行頁(yè)面跳轉(zhuǎn),用戶的個(gè)人信息還是不會(huì)顯示,這是因?yàn)間etUserInfomation事件處理函數(shù)點(diǎn)擊組件時(shí)才觸發(fā),我們需要在頁(yè)面加載時(shí)也能觸發(fā)獲取用戶信息才行。

我們可以在login.js的onLoad生命周期函數(shù)里輸入以下代碼,當(dāng)用戶授權(quán)之后來(lái)調(diào)用wx.getUserInfo() API:

wx.getSetting({
  success: res => {
    if (res.authSetting['scope.userInfo']) {
      wx.getUserInfo({
        success: res => {
          let { avatarUrl, city, nickName } =res.userInfo
          this.setData({
            avatarUrl, city, nickName
          })
        }
      })
    }
  }
});

這樣當(dāng)我們加載頁(yè)面時(shí),用戶的信息就能顯示出來(lái)了,不過(guò)這里的頭像是從API里重新取的,也會(huì)不清晰。我們當(dāng)然可以像之前一樣把頭像的鏈接替換一下,但是如果每個(gè)頁(yè)面都這么寫就會(huì)很麻煩,解決的方法有2種,一種是把高清頭像存儲(chǔ)到緩存里,還有一種是把代碼封裝成一個(gè)組件(大家可以自己研究如何自定義組件了)。

openid、用戶信息與登錄

盡管我們已經(jīng)獲取到了用戶的頭像、昵稱等信息,但是這不能稱之為真正意義的登錄,只有獲取到了用戶身份的唯一ID也就是openid,我們才能把用戶行為比如點(diǎn)贊、評(píng)論、發(fā)布文章、收藏等與用戶掛鉤,用戶這些行為都與數(shù)據(jù)庫(kù)有關(guān),而能夠確定點(diǎn)贊、評(píng)論、文章、收藏這些數(shù)據(jù)與用戶關(guān)系的就是openid,也就是說(shuō)只要獲取到了openid就意味著用戶已經(jīng)登錄,而獲取用戶信息(如頭像、昵稱)不過(guò)是一個(gè)附加服務(wù),這兩個(gè)是可以完全獨(dú)立的。沒有openid,我們也無(wú)法把用戶信息給存儲(chǔ)到數(shù)據(jù)庫(kù),也就沒法讓用戶自定義用戶信息。無(wú)論是用戶行為,還是用戶的信息,openid都是一個(gè)重要的橋梁。

通過(guò)前面的login云函數(shù),我們就已經(jīng)可以獲取到用戶的openid。無(wú)需維護(hù)復(fù)雜的鑒權(quán)機(jī)制,即可獲取天然可信任的用戶登錄態(tài)(openid),是云開發(fā)的一個(gè)重要優(yōu)勢(shì)。無(wú)論是云存儲(chǔ)還是云數(shù)據(jù)庫(kù),openid都扮演著一個(gè)重要的角色。

小程序端上傳圖片到云存儲(chǔ)

要把圖片上傳到云存儲(chǔ),會(huì)使用到wx.cloud.uploadFile,這個(gè)API是小程序端的API,它是把本地資源也就是臨時(shí)文件里的文件上傳到云存儲(chǔ)里。在前面《圖片、緩存與文件》章節(jié)里我們已經(jīng)了解到如何把圖片上傳到小程序的臨時(shí)文件,而要把臨時(shí)文件上傳到云存儲(chǔ),則需要調(diào)用wx.cloud.uploadFile API。

技術(shù)文檔:wx.cloud.uploadFile

在wx.cloud.uploadFile技術(shù)文檔里,可以看到要調(diào)用API,需要獲取圖片的filePath,在小程序里為臨時(shí)文件的路徑,也就是要把上傳到小程序的臨時(shí)文件路徑賦值給它;還有一個(gè)cloudPath,這個(gè)為文件的云存儲(chǔ)路徑,這個(gè)是我們可以任意設(shè)置的。

使用開發(fā)者工具在login.wxml里添加以下代碼,代碼和前面章節(jié)基本一致,大家也可以回顧一下以前的內(nèi)容:

<button bindtap="chooseImg">選擇圖片</button>
<image mode="widthFix" src="{{imgurl}}"></image>

然后在login.js的data里初始化imgurl,這里imgurl是一個(gè)字符串,

  data: {
    imgurl: "",
  },

然后在login.js里添加事件處理函數(shù)chooseImg,我們?cè)賮?lái)回顧一下臨時(shí)文件的知識(shí):

  chooseImg: function () {
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: function (res) {
        console.log(res)
        console.log(res.tempFilePaths)
      }
    })
  },

編譯后,上傳一張圖片,在控制臺(tái)里我們可以看到res.tempFilePaths是一個(gè)數(shù)組格式,而wx.cloud.uploadFile的filePath是一個(gè)字符串,所以我們?cè)谏蟼鲿r(shí),可以把第一張圖片的路徑(字符串)賦值給filePath:

const filePath = res.tempFilePaths[0]

文件名與后綴的處理

我們知道一個(gè)文件由文件名稱和文件后綴構(gòu)成,比如tcb.jpg和cloudbase.png,jpeg說(shuō)明圖片的格式是JPG格式,而png說(shuō)明圖片是PNG格式,文件名稱相同且格式相同就是出現(xiàn)覆蓋,如果我們隨意更改了文件的后綴,大多數(shù)文件就會(huì)打不開。所以要把cloudPath云存儲(chǔ)的路徑需要我們把文件名和后綴給處理好。

當(dāng)我們把圖片上傳到小程序的臨時(shí)文件后,我們可以查看一下臨時(shí)路徑是什么樣子的:

http://tmp/wx7124afdb64d578f5.o6zAJs291xB-a5G1FlXwylqTqNQ4.esN9ygu5Hmyfccd41d052e20322e6f3469de87f662a0.png

臨時(shí)路徑的文件名就不是原來(lái)的文件名,會(huì)變成一段長(zhǎng)字符,但文件的格式還是原來(lái)的文件格式(后綴)。那cloudPath要輸入文件的路徑,就需要填寫文件名和文件格式,這個(gè)要怎么處理呢?

在上一節(jié)的QuickStart小程序里,文件上傳到云存儲(chǔ)的處理方式如下:

const cloudPath = 'my-image' + filePath.match(/\.[^.]+?$/)[0]

也就是它把上傳的所有圖片都命名為my-image,而文件的后綴還是原來(lái)的文件后綴(也就是文件格式不變)。這里的filePath.match(/.[^.]+?$/)[0]是字符串的正則處理,后面我們會(huì)來(lái)詳細(xì)了解。我們先可以在開發(fā)者工具的控制臺(tái)輸入以下代碼了解一下它的功能:

const filepath="http://tmp/wx7124afdb64d578f5.o6zAJs291xB-a5G1FlXwylqTqNQ4.esN9ygu5Hmyfccd41d052e20322e6f3469de87f662a0.png"
filepath.match(/\.[^.]+?$/)[0]

打印可以得到臨時(shí)文件的后綴,這里為.png。這種把所有文件都命名為my-image的做法,會(huì)導(dǎo)致當(dāng)文件的后綴相同時(shí)文件會(huì)被覆蓋,如果不希望文件被覆蓋,我們需要給文件命不同的名字,我們可以這樣處理:

const cloudPath = `${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]

給文件名加上時(shí)間戳和一個(gè)隨機(jī)數(shù),時(shí)間戳是以毫秒計(jì)算,而隨機(jī)數(shù)是以1000內(nèi)的正整數(shù),除非1秒鐘(1秒=1000毫秒)上傳幾十萬(wàn)張照片,不然文件名是不會(huì)重復(fù)的。

結(jié)合上面的內(nèi)容,我們可以把wx.chooseImage()的success回調(diào)函數(shù)如下處理:

success: function (res) {
  const filePath = res.tempFilePaths[0]
  const cloudPath = `${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]
  wx.cloud.uploadFile({
    cloudPath,
    filePath,
    success: res => {
      console.log('上傳成功后獲得的res:', res)
    },
  })
}

編譯之后,我們?cè)俅紊蟼饕粡垐D片就會(huì)打印上傳成功之后的res對(duì)象,里面包含圖片在云存儲(chǔ)里的fileID,注意它的文件名和文件后綴,以及我們可以在云開發(fā)控制臺(tái)的存儲(chǔ)里找到你上傳的圖片,也就是說(shuō)我們上傳圖片到云存儲(chǔ)是無(wú)法直接獲取到圖片的下載地址的。

云存儲(chǔ)的二級(jí)目錄

在存儲(chǔ)里我們都是把所有的圖片放在根目錄下,沒有二級(jí)目錄,那我們能不能建一個(gè)二級(jí)目錄呢?當(dāng)然是可以的,我們可以在cloudPath的前面加一個(gè)文件路徑就可以了,比如:

const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]

渲染云存儲(chǔ)圖片到組件

在上一節(jié)組件支持部分了解到,我們是可以把fileID直接在小程序的某些組件里渲染出來(lái)的。綜合以上內(nèi)容chooseImg事件處理函數(shù)最終為以下代碼(注意this.setData的this指向,這里為了方便把success回調(diào)都寫成了箭頭函數(shù)):

  chooseImg: function () {
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: res=> {
        const filePath = res.tempFilePaths[0]
        const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]
        wx.cloud.uploadFile({
          cloudPath,
          filePath,
          success: res => {
            console.log('上傳成功后獲得的res:', res)
            const imgurl=res.fileID            
            this.setData({
              imgurl
            })
          },
        })
      }
    })
  },
在云開發(fā)控制臺(tái)的存儲(chǔ)里,我們可以看到每張圖片的詳細(xì)信息都有上傳者 Open ID,無(wú)論你是使用開發(fā)者工具在模擬器的小程序里上傳還是預(yù)覽在手機(jī)的小程序里上傳,只要你用的是同一個(gè)微信賬號(hào),這個(gè)上傳者openid都是一致的,云存儲(chǔ)會(huì)自動(dòng)記錄上傳者的openid。

小任務(wù):結(jié)合《圖片、緩存與文件》章節(jié)里的wx.chooseMessageFile()的知識(shí),將客戶端會(huì)話(微信聊天窗口)里的視頻、音頻、PDF、Excel等也上傳到云存儲(chǔ)里。

云函數(shù)上傳圖片到云存儲(chǔ)

云開發(fā)不僅在小程序端可以上傳文件到云存儲(chǔ),還可以通過(guò)云函數(shù)也就是云端上傳圖片到云存儲(chǔ)(這里會(huì)涉及到一點(diǎn)Nodejs的知識(shí))。

技術(shù)文檔:uploadFile

注意云函數(shù)上傳圖片的API屬于服務(wù)端API,與wx.cloud.uploadFile是小程序端API不同。

使用開發(fā)者工具右鍵點(diǎn)擊云函數(shù)根目錄也就是cloudfunctions文件夾,選擇新建Node.js云函數(shù),云函數(shù)的名稱命名為uploadimg,右鍵點(diǎn)擊uploadimg文件夾,選擇硬盤打開,然后拷貝一張圖片如demo.jpg進(jìn)去,文件結(jié)構(gòu)如下:

uploadimg云函數(shù)目錄        
├── index.js 
├── package.json 
├── demo.jpg

然后打開index.js,輸入以下代碼:

const cloud = require('wx-server-sdk')
const fs = require('fs')
const path = require('path')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
  const fileStream = fs.createReadStream(path.join(__dirname, 'demo.jpg'))
  return await cloud.uploadFile({
    cloudPath: 'tcbdemo.jpg',
    fileContent: fileStream,
  })
}

然后右鍵點(diǎn)擊uploadimg文件夾,選擇在終端中打開,輸入npm install安裝依賴,再點(diǎn)擊uploadimg文件夾,選擇上傳并部署所有文件(這時(shí)圖片也一并上傳到了云端)。

由于云端測(cè)試無(wú)法獲取用戶登陸態(tài)信息,所以我們不能在云端測(cè)試?yán)锇褕D片上傳到云存儲(chǔ),需要在小程序端調(diào)用,使用開發(fā)者工具在login.wxml輸入以下代碼,也就是新建一個(gè)綁定uploadimg事件處理函數(shù)的button用于觸發(fā):

<button bindtap="uploadimg">云函數(shù)上傳圖片</button>

然后在login.js里輸入以下代碼,在事件處理函數(shù)uploadimg里調(diào)用uploadimg云函數(shù),并返回調(diào)用之后的res對(duì)象:

  uploadimg() {
    wx.cloud.callFunction({
      name: 'uploadimg',
      success: res => {
        console.log(res)
      }
    })
  },

編譯之后,點(diǎn)擊云函數(shù)上傳圖片按鈕,就可以調(diào)用uploadimg云函數(shù),從而調(diào)用uploadFile API將服務(wù)端/云端的圖片上傳到云存儲(chǔ)里面啦,可以打開云開發(fā)控制臺(tái)的云存儲(chǔ)查看是否有tcbdemo.jpg這張圖片。

注意,通過(guò)這種方式上傳到云存儲(chǔ)的圖片,是沒有上傳者 Open ID的,在云存儲(chǔ)里查看這張圖片的詳細(xì)信息,就可以了解到。

調(diào)用數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)的導(dǎo)入

在調(diào)用數(shù)據(jù)庫(kù)之前,我們需要先有一個(gè)比較貼近實(shí)際的數(shù)據(jù)庫(kù)案例,為此把前面章節(jié)用到的知乎日?qǐng)?bào)數(shù)據(jù)整理出了一個(gè)數(shù)據(jù)庫(kù)文件。云開發(fā)數(shù)據(jù)庫(kù)支持用文件的方式導(dǎo)入已有的數(shù)據(jù)(這里推薦大家使用json)。

數(shù)據(jù)庫(kù)下載:知乎日?qǐng)?bào)文章數(shù)據(jù)

右鍵點(diǎn)擊鏈接,將data.json存儲(chǔ)到電腦。為了方便大家閱讀與編輯data.json文件的內(nèi)容,推薦大家使用Visual Studio Code編輯器。

代碼編輯器:Visual Studio Code

編輯器的漢化與插件:可能你安裝的VS Code的界面是英文的,可以參照VSCode設(shè)置中文顯示,將VS Code漢化。

使用VS Code編輯器打開data.json,發(fā)現(xiàn)數(shù)據(jù)的內(nèi)容與寫法我們都比較熟悉,知識(shí)各個(gè)記錄對(duì)象之間是使用回車 \n 分隔,而不是逗號(hào),這一點(diǎn)需要大家注意。

打開云開發(fā)控制臺(tái),在數(shù)據(jù)庫(kù)里新建一個(gè)集合zhihu_daily,導(dǎo)入該json文件,導(dǎo)入時(shí)會(huì)有沖突模式選擇,看下面的介紹,推薦大家使用upsert:

  • Insert:總是插入新記錄
  • Upsert:如果記錄存在則更新,否則插入新記錄

導(dǎo)入后,發(fā)現(xiàn)數(shù)據(jù)庫(kù)自動(dòng)給每一條數(shù)據(jù)(記錄)都加了唯一的標(biāo)識(shí)_id。

小程序端調(diào)用數(shù)據(jù)庫(kù)

在小程序端調(diào)用數(shù)據(jù)庫(kù)的方式很簡(jiǎn)單,我們可以把下面的代碼寫到一個(gè)事件處理函數(shù)里,然后點(diǎn)擊組件觸發(fā)事件處理函數(shù)來(lái)調(diào)用;也可以直接寫到頁(yè)面的生命周期函數(shù)里面;還可以把它寫到app.js小程序的生命周期函數(shù)里面。

使用開發(fā)者工具,將下面的代碼寫到login.js的onLoad函數(shù)里面,我們

  • 先使用wx.cloud.database()獲取數(shù)據(jù)庫(kù)的引用(相當(dāng)于連接數(shù)據(jù)庫(kù));
  • 再使用db.collection()獲取集合的引用;
  • 再通過(guò)Collection.get來(lái)獲取集合里的記錄.

const db = wx.cloud.database()
db.collection('zhihu_daily')
  .get()
  .then(res => {
    console.log(res.data)
  })
  .catch(err => {
    console.error(err)
  })

編譯之后,就能在控制臺(tái)看到調(diào)用的20條數(shù)據(jù)庫(kù)記錄了(如果沒有指定 limit,則默認(rèn)最多取 20 條記錄)。

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

使用云函數(shù)也可以調(diào)用數(shù)據(jù)庫(kù),使用開發(fā)者工具右鍵點(diǎn)擊云函數(shù)根目錄也就是cloudfunctions文件夾,選擇新建Node.js云函數(shù),云函數(shù)的名稱命名為zhihu_daily,然后打開index.js,輸入以下代碼:

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
exports.main = async (event, context) => {
  return await db.collection('zhihu_daily')
    .get()
}

然后右鍵點(diǎn)擊index.js,選擇云函數(shù)增量上傳:更新文件,我們既可以使用云函數(shù)的本地調(diào)試(要本地調(diào)試需要使用npm install安裝wx-server-sdk依賴),也可以使用云端測(cè)試來(lái)了解云函數(shù)調(diào)用數(shù)據(jù)庫(kù)的情況。

openid與數(shù)據(jù)庫(kù)

在云開發(fā)控制臺(tái)的數(shù)據(jù)庫(kù)標(biāo)簽里,打開上一節(jié)內(nèi)容里的counters集合,在這個(gè)集合里我們可以看到每條記錄除了有_id字段以外,還有一個(gè)_openid字段用來(lái)標(biāo)志每條記錄的創(chuàng)建者(也就是小程序的用戶)。但是在我們使用管理端(控制臺(tái)和云函數(shù))中創(chuàng)建的數(shù)據(jù)比如我們之前導(dǎo)入的zhihu_daily,就不會(huì)有 _openid 字段,因?yàn)檫@些記錄屬于管理員(不是用戶)創(chuàng)建的記錄。

我們可以自定義 _id(也就是給數(shù)據(jù)添加一個(gè)_id字段并填入任意值),但不可自定義和修改 _openid 。 _openid 是在文檔創(chuàng)建時(shí)由系統(tǒng)根據(jù)小程序用戶默認(rèn)創(chuàng)建的,可以用來(lái)標(biāo)識(shí)和定位文檔。和云存儲(chǔ)一樣,數(shù)據(jù)庫(kù)的記錄也和openid有著緊密的聯(lián)系。

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)