- 前端進階之旅:https://interview2.poetries.top
- 博客:https://blog.poetries.top
- 公號:「前端進階之旅」 每天分享技術干貨,學前端不迷路
- 作者:程序員poetry
基本簡介
微信云托管是什么?
- 微信云托管 是微信團隊提供的以云原生為基礎的,免運維、高可用服務上云解決方案,無需服務器,1分鐘即可部署小程序/公眾號服務端。
- 微信云托管支持目前絕大多數語言/框架項目,開發(fā)者可以從服務器平滑遷移;并且微信云托管的自動運維和擴縮容特性,無需開發(fā)者關心服務的可用性,專注于業(yè)務,極大節(jié)省人力和服務資源成本。
- 同時,微信云托管還集成持續(xù)交付部署,DevOps自動化,安全鑒權等眾多能力,致力于幫助沒有深層運維經驗的業(yè)務開發(fā)者和研發(fā)團隊,用最低的成本,打造出穩(wěn)定性高,安全性強的后端服務。
- 最重要的,微信云托管與微信生態(tài)深度融合,具有免鑒權,云調用,消息推送,微信支付等眾多微信優(yōu)勢特性,開發(fā)者可以非常輕松和高效的完成互通,并且在安全、可靠性方面有微信團隊的專業(yè)保障。

架構特點
微信云托管以容器服務為核心,提供方便易用的存儲體系、微信生態(tài)、安全鑒權等服務能力;搭配簡單易懂的操作面板,集成資源監(jiān)控,資源告警,流水線等自動化功能,是一站式的后端云服務。
微信云托管使用目前主流的容器平臺Docker以及容器編排技術Kubernetes(簡稱K8S),來管理你的項目

常見問題
云托管的作用是什么?
代替服務器部署小程序/公眾號后端。
微信云托管和微信云開發(fā)的區(qū)別是什么,如何選擇?
- 微信云開發(fā)和微信云托管都是微信聯(lián)合騰訊云打造的微信云服務生態(tài)的組成部分,都提供了免服務器免運維的能力,開發(fā)者可以根據自己的業(yè)務特點進行選擇。
- 微信云開發(fā)以云函數提供計算能力,圍繞 Node.js 技術棧,適合前端開發(fā)者簡單快捷實現(xiàn)后端功能,或全棧開發(fā)者一體化開發(fā); 微信云托管以容器提供計算能力,支持任意后端語言和框架,適合前后端分離項目的后端開發(fā)、傳統(tǒng)模式后端項目遷移,對團隊協(xié)作和企業(yè)級應用場景更友好
微信云托管和云開發(fā)中的云托管有何區(qū)別?
- 微信云托管和之前云托管的區(qū)別除了品牌升級外,還做了獨立的控制臺。舊的云托管只是云開發(fā)的一個模塊,只有單純的容器引擎能力,升級為微信云托管后脫離云開發(fā),成為完整的后端項目托管解決方案。 從代碼管理到CI/CD流水線部署發(fā)布,提供全鏈路、低成本、企業(yè)級的云原生解決方案,功能更強大、體驗更友好
- 云開發(fā)中的云托管能力已停止功能更新,僅支持存量業(yè)務繼續(xù)運行。建議原云開發(fā)中的云托管的用戶盡快將項目遷移到微信云托管。
微信云托管可以用于APP/網站/其他平臺小程序嗎?
必須先有微信小程序/公眾號才可以開通微信云托管,但部署在微信云托管上的服務可以通過公網訪問,因此可以被APP/網站/其他平臺小程序的前端調用,只是無法享受 callcontainer 內部鏈路帶來的安全防DDoS/請求加速等優(yōu)勢。
微信云托管的環(huán)境可以在微信開發(fā)者工具的云開發(fā)控制臺中看到嗎?
微信云托管和微信云開發(fā)是兩套獨立體系,微信云托管的環(huán)境只能在微信云托管控制臺看到,在微信開發(fā)者工具的云開發(fā)控制臺中不能看到
騰訊云和微信云托管有關系嗎?云開發(fā)的云托管和微信云托管有什么區(qū)別?
微信云托管是整合了騰訊云底層資源和微信生態(tài)鏈路的綜合解決方案。原云開發(fā)中的云托管獨立出來,升級為微信云托管,補充數據庫、ci/cd、灰度發(fā)布等更多完整后端功能和企業(yè)級devops能力。
云托管的時間相差8個小時?
容器系統(tǒng)時間默認為 UTC 協(xié)調世界時間 (Universal Time Coordinated),與本地所屬時區(qū) CST (上海時間)相差 8 個小時:
在構建基礎鏡像或在基礎鏡像的基礎上制作自定義鏡像時,在 Dockerfile 中創(chuàng)建時區(qū)文件即可解決單一容器內時區(qū)不一致問題,且后續(xù)使用該鏡像時,將不再受時區(qū)問題困擾。
- 打開
Dockerfile文件。 - 寫入以下內容,配置時區(qū)文件
FROM centos as centos COPY --from=centos /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo "Asia/Shanghai" > /etc/timezone
- 重新構建容器鏡像,使用新的鏡像重新部署。或直接上傳含新的 Dockerfile 的代碼包重新部署
云托管部署
云托管模板部署




小程序/公眾號中調用
// 在小程序 app.js中初始化云托管
onLaunch() {
if (!wx.cloud) {
console.error('請使用 2.2.3 或以上的基礎庫以使用云能力')
} else {
wx.cloud.init({
env: 'xxx', // 填入云托管環(huán)境ID
})
}
}
// 在小程序中調用云托管服務
wx.cloud.callContainer({
"config": {
"env": "prod-xx" // 填入云托管環(huán)境ID
},
"path": "/api/count", // 云托管服務請求路徑
"header": {
"X-WX-SERVICE": "express-4bnl" // 云托管服務名稱
},
"method": "POST",
"data": {
"action": "inc" // 發(fā)起請求傳入的參數
}
})
云托管自定義部署nestjs
初始化您的 Nest.js 項目
npm i -g @nestjs/cli
nest new nest-app
在根目錄下,執(zhí)行以下命令在本地直接啟動服務。
cd nest-app && npm run start
打開瀏覽器訪問 http://localhost:3000,即可在本地完成 Nest.js 示例項目的訪問。
新建服務


點擊發(fā)布后,云托管會執(zhí)行Dockerfile構建流水線,到日志可以查看構建進度


微信云托管部署成功后,可以在實例列表,點擊進入容器看到代碼,這里里面的內容不能修改,在容器啟動后會覆蓋


調試接口

CLI工具使用
npm install -g @wxcloud/cli
wxcloud -h
獲取 CLI 密鑰
CLI工具的登錄采用了密鑰形式,在使用前需要前往微信云托管控制臺 - 設置 -CLI 密鑰生成,生成時需要賬號管理員掃碼,可以新建多個密鑰,用于在不同地方使用。
傳入微信 APPID 和CLI密鑰,操作登錄
wxcloud login [OPTIONS]
查看登錄賬號下所有的環(huán)境列表
wxcloud env:list [OPTIONS]
查看指定環(huán)境下的所有服務列表
wxcloud service:list [OPTIONS]

云托管本地調試
本地docker調試
- 安裝docker
- 安裝微信開發(fā)者工具最新版
- 安裝vscode Docker拓展
- 在 VSCode 拓展欄搜索 weixin-cloudbase 然后安裝
以koa作為后端演示
全局安裝 koa-generator 腳手架.
npm install -g koa-generator
創(chuàng)建項目
# 使用ejs引擎
koa2 -e wxcloud-debug-koa
cd wxcloud-debug-koa // 進入項目根目錄
npm install // 安裝項目依賴
- 修改
www/bin中的端口為9000 - 修改
routes/index中代碼為
router.get('/', async (ctx, next) => {
ctx.body = {
message: '請求頭',
header: ctx.header
}
})
打開瀏覽器訪問 http://localhost:9000,即可在本地完成 koa 示例項目的訪問。
編寫dockerfile
FROM daocloud.io/library/node:14.7.0
# 設置時區(qū)
ENV TZ=Asia/Shanghai \
DEBIAN_FRONTEND=noninteractive
RUN ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata && rm -rf /var/lib/apt/lists/*
RUN mkdir -p /app
# 指定工作目錄
WORKDIR /app
# 復制當前代碼到/app工作目錄
COPY . ./
# npm 源,選用國內鏡像源以提高下載速度
RUN npm config set registry https://registry.npm.taobao.org/
# npm 安裝依賴
RUN npm install
# 啟動服務
CMD node app.js
EXPOSE 9000
如只在 VSCode 中同時編輯調試一個服務,
可直接打開服務代碼目錄作為根目錄(暫不支持 VSCode Workspace 工作區(qū)),保證根目錄下有Dockerfile文件,插件面板中會顯示該服務的名字


調試過程中因需要獲取微信信息,會使用云托管 CLI Key,因此需在 VSCode 插件配置填入小程序 appid 和 cli key,點擊插件面板的 ? 圖標打開配置:


構建鏡像,啟動容器
右鍵服務名,選擇 start,將構建鏡像并啟動容器

可以看到構建過程

啟動容器需要相應的容器配置信息(.cloudbase/container/debug.json),如果沒有會提示創(chuàng)建,配置文件字段和含義如下:

其中需特別注意端口號
containerPort、Dockerfile路徑dockerfilePath、自定義環(huán)境變量envParams
此時出現(xiàn)異常,我們修改.cloudbase/container/debug.json中的containerPort為koa服務中定義的9000端口,重新構建即可


容器構建和啟動成功后,在插件面板狀態(tài) icon 會相應更新:

也可以通過docker ps查看已啟動的服務

我們在云托管后臺可以看到此時默認啟動了一個調試服務,我們不要去修改它

此時可以請求容器了,在插件面板旁會展示兩個端口號,通過第一個端口訪問容器會帶有微信相關信息(header 中包含 appid 等),通過第二個端口訪問容器不會帶有微信相關信息而是直接請求到容器內部,右鍵服務選擇 Open in browser (via WX server) 和 Open in browser (no WX auth) 可以在瀏覽器中打開,分別對應這兩種情況,也可以寫代碼或通過 POSTMAN 等工具請求

請求不經過微信服務器返回:http://127.0.0.1:27081/
不帶微信信息的端口,直接訪問即可,適合在瀏覽器調試

請求經過微信服務器返回:http://127.0.0.1:27082/
微信端口,請求時會模擬微信用戶信息的 Header,如 x-wx-openid,適合微信開發(fā)者工具中使用

在微信開發(fā)者工具中,可以選擇連接到 VSCode 啟動的容器,從而在小程序模擬器中訪問本地云托管容器
此能力需要使用微信開發(fā)者工具 v1.05.2202242 及以上版本,并更新 VSCode 插件到 v1.0.12 以上。
創(chuàng)建一個小程序測試項目

在 微信開發(fā)者工具 的
Docker面板中,找到 「Running Containers」,右擊容器名稱,選擇Attach Weixin Devtools,即可在小程序代碼中,使用wx.cloud.callContainer訪問容器。

需要退出再次Detach Weixin Devtools

調用時,需要注意
Header中的X-WX-SERVICE需要與容器名保持一致
修改小程序app.js代碼
// app.js
App({
onLaunch: async function () {
await wx.cloud.init({
// env: "其他云開發(fā)環(huán)境,也可以不填" // 此處 init 的環(huán)境 ID 和微信云托管沒有作用關系,沒用就留空
});
const res = await wx.cloud.callContainer({
config: {
env: "prod-xx", // 微信云托管環(huán)境ID,不能為空,替換自己的
},
path: '/',
method: 'GET',
header: {
'X-WX-SERVICE': 'wxcloud-debug-koa', // 替換成本地要調試的容器名稱
}
});
console.log(res); // 在控制臺里查看打印
}
})

查看請求日志

或者通過docker logs查看

進入終端
如果需要進入到容器內部終端調試定位問題,可以右鍵服務名選擇 Attach Shell 進入容器內終端

本地docker實時調試
通過微信云托管 VSCode 插件,可以實現(xiàn)實時開發(fā),即代碼變動時,不需要重新構建和啟動容器,即可查看變動后的效果。
選擇 Live Coding

右鍵點擊需要調試的容器,選擇
Live Coding,將自動生成Dockerfile.development和docker-compose.yml2 個文件并啟動容器。
如果生成失敗,我們需要自行配置

開發(fā)模式的 docker-compose.yml
# 開發(fā)模式的 docker-compose.yml
# 實時開發(fā)將使用項目目錄下的 docker-compose.yml 將當前目錄映射到容器中。
# 大多數情況下,插件將根據項目的 Dockerfile 自動生成本文件,不需要手動編寫。
version: '3'
services:
app:
build:
context: . # 構建上下文
dockerfile: Dockerfile.development
volumes:
- .:/app # 需要映射的目錄(即代碼目錄)
- /app/node_modules # 映射 node_modules 目錄,如果有構建產物與代碼目錄同級,需要單獨映射避免無法運行
ports:
- 27081:9000 # 監(jiān)聽端口,主機端口:容器端口 修改為koa服務端口
container_name: wxcloud_wxcloud-debug-koa # 容器名稱
labels: # 容器標簽,一般不需改動
- wxPort=27082
- hostPort=27081
- wxcloud=wxcloud-debug-koa
- role=container
environment:
# 使用本地調試 MySQL 時,需要填入如下環(huán)境變量,并啟動 MySQL 代理服務
- MYSQL_USERNAME=
- MYSQL_PASSWORD=
- MYSQL_ADDRESS=
networks:
default:
external:
name: wxcb0 # 容器網絡打通,一般不需改動
修改端口 9000
ports:
- 27081:9000 # 監(jiān)聽端口,主機端口:容器端口 修改為koa服務端口
實時開發(fā)使用項目目錄下的 Dockerfile.development
# Dockerfile.development
# 實時開發(fā)使用項目目錄下的 Dockerfile.development 作為開發(fā)期間的容器的 Dockerfile
# 大多數情況下,插件將根據項目的 Dockerfile 自動生成本文件,不需要手動編寫。
# 開發(fā)模式的 Dockerfile 與正式模式的 Dockerfile 的區(qū)別在于:
# 單階段構建
# 將編譯命令轉換為啟動命令,如 Spring Boot 模板的 mvn package 會轉換為 spring-boot:run
# 拉取實時開發(fā)的工具套件,安裝到 /usr/bin 下
# 通過實時開發(fā)工具套件啟動用戶程序,在代碼發(fā)生更改時,自動重啟進程。
# Auto-generated by weixin cloudbase vscode extension
FROM ccr.ccs.tencentyun.com/weixincloud/wxcloud-livecoding-toolkit:latest AS toolkit
FROM node:lts-slim
COPY --from=toolkit nodemon /usr/bin/nodemon
# 設置時區(qū)
RUN ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
# --only=production 只安裝生產環(huán)境的依賴
RUN npm install --only=production && npm install pm2 -g
COPY . ./
# 修改nest啟動入口 node bin/www
CMD [ "nodemon", "-x", "node bin/www", "-w", "/app", "-e", "java, js, mjs, json, ts, cs, py, go" ]
修改koa啟動入口
node www/bin

啟動實時服務

修改本地代碼,不用重啟容器即可查看效果
本地調試中使用「開放接口服務」
- 在 VSCode 拓展欄搜索
weixin-cloudbase然后安裝 - 完成配置后,在左側
Docker面板內,右擊Proxy nodes for VPC access中的api.weixin.qq.com,點擊啟動(Start) - 右擊用戶容器,點擊啟動(
Start),容器內即可訪問本地云調用
填入環(huán)境ID

啟動api.weixin.qq.com服務

啟動自己的業(yè)務服務,在業(yè)務服務運行過程中,啟動 vpc 中的 api.weixin.qq.com 服務
插件將會在你的云托管環(huán)境中開啟一個代理服務,用于和本地
api.weixin.qq.com服務,同時和業(yè)務服務共享同一個網絡,就實現(xiàn)了本地的「開放接口服務」,需要注意,本地調試中只是模擬了業(yè)務服務的所處環(huán)境,不是真實的線上部署情況。
云托管中使用云調用
云調用是具有「免鑒權調用微信開放服務接口」特性的能力,是云開發(fā)/云托管中微信生態(tài)的一部分。
在云調用出現(xiàn)之前,微信開放服務接口的正常調用,需要開發(fā)者使用密鑰信息獲取access_token,并自己維護 token 的有效期和安全。而獲取access_token,涉及到密鑰交互請求,容易暴漏密鑰導致被盜用,對開發(fā)者和微信服務都有消極的影響。
云調用主要打造免鑒權,也就是免密鑰,全程不暴漏任何信息,開發(fā)者無需維護access_token,那對于接口請求的合法性判定,完全由與微信同鏈路的微信云托管參與實施。
配置云調用權限
前往控制臺 - 云調用 - 云調用權限配置,按照自己的業(yè)務需要配置接口。
比如你要在服務中調用文字安全檢測接口
此接口的調用地址如下:https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN
在配置時,只需要 api.weixin.qq.com 之后,?參數之前的部分,所以應該在配置輸入框里填寫如下
/wxa/msg_sec_check

在云托管服務中,微信后臺周期性的將開放接口所必須要的
access_token,推送到服務的容器實例中。在使用時只需要從容器本地讀取令牌,就可以包裝請求去調用了:
access_token推送的時間間隔為10分鐘,令牌的有效期為30分鐘; 掛載路徑為:/.tencentcloudbase/wx/cloudbase_access_token; 在同一個環(huán)境中所有的容器實例,推送的access_token相同
查看容器內access_token


如果需要獲取容器內的access_token調試接口,需要在接口中填入cloudbase_access_token=容器內的access_token
// https://developers.weixin.qq.com/miniprogram/dev/wxcloudrun/src/guide/weixin/token.html
const fs = require('fs')
const request = require('request')
// 容器內的access_token
const token = fs.readFileSync('/.tencentcloudbase/wx/cloudbase_access_token', 'utf-8')
return new Promise((resolve, reject) => {
request({
method: 'POST',
// 可本地調試用cloudbase_access_token
url: `https://api.weixin.qq.com/wxa/msg_sec_check?cloudbase_access_token=${token}`,
body: JSON.stringify({
openid: '用戶的openid', // 可以從請求的 header 中直接獲取 req.headers['x-wx-openid']
version: 2,
scene: 2,
content: '安全檢測文本'
})
},function (error, response) {
console.log('接口返回內容', response.body)
resolve(JSON.parse(response.body))
})
})
云托管內調用服務端文字檢測接口
npm i request request-promise -S
在代碼routes/home中添加
router.get('/msg_sec_check', async (ctx, next) => {
let ACCESS_TOKEN = ''
let data = await rp({
method: 'POST',
// 在云托管容器環(huán)境中,可以拿到access_token,而且免鑒權、這里不需要填寫
// https://developers.weixin.qq.com/miniprogram/dev/wxcloudrun/src/guide/weixin/open.html
// 這里填http協(xié)議、在云托管中不需要填access_token、需要在云托管-云調用中填寫接口白名單前綴、開啟側邊欄proxy代理后可以免輸入本地調試
uri: `http://api.weixin.qq.com/wxa/msg_sec_check`,
body: {
openid: ctx.header['x-wx-openid'], // 用戶的openid 可以從請求的 header 中直接獲取 req.headers['x-wx-openid']
version: 2,
scene: 2,
content: '安全檢測文本'
},
json: true
}).catch(error=>{
ctx.body = {
code: -1,
message: error
}
throw error
})
ctx.body = {
data,
code: 200
}
})
在云托管權限控制臺添加接口權限

開啟 api.poetries.top 本地調試服務

通過微信服務器模擬小程序請求


也可以在小程序中訪問

云托管內調用服務端云函數接口
在代碼routes/home中添加
// 云托管內調用云函數
router.get('/call-fn-banner', async (ctx, next) => {
const ACCESS_TOKEN = ''
const weappEnvId = 'poetry-prod-6gj3fpxa137552a6' // 小程序云開發(fā)envId
const data = await rp({
method: 'POST',
// 在云托管容器環(huán)境中,可以拿到access_token,而且免鑒權、這里不需要填寫
// https://developers.weixin.qq.com/miniprogram/dev/wxcloudrun/src/guide/weixin/open.html
// 這里填http協(xié)議、在云托管中不需要填access_token、需要在云托管-云調用中填寫接口白名單前綴、開啟側邊欄proxy代理后可以免輸入本地調試
uri: `http://api.weixin.qq.com/tcb/invokecloudfunction?env=${weappEnvId}&name=banner`,
body: {
$url: 'queryBanner',
...ctx.request.query
},
json: true
}).then(async res=>{
console.log('callCloudFn res', res)
if(res && res.errcode === 40001) {
throw error
}
let data = res.resp_data ? JSON.parse(res.resp_data) : {}
return data
}).catch(error=>{
ctx.body = {
code: error.errcode,
message: error.errmsg
}
throw error
})
ctx.body = data
})
小程序云函數banner代碼

// 云函數入口文件
const cloud = require('wx-server-sdk')
cloud.init({
env: 'poetry-prod-xx' // 環(huán)境ID
})
const TcbRouter = require('tcb-router')
const db = cloud.database()
const bannersCollection = db.collection('banners') // banners集合
// 云函數入口函數
exports.main = async (event, context) => {
const app = new TcbRouter({event})
// banner列表
app.router('queryBanner', async (ctx,next)=>{
const {pageSize = 20, pageNum = 1, orderBy, sort} = event
try {
let data = await bannersCollection.skip(Number((pageNum - 1)*pageSize)).limit(Number(pageSize)).orderBy(orderBy || 'createTime', sort || 'desc').get().then(res=>res.data)
let {total} = await bannersCollection.count()
ctx.body = {
message: '查詢成功',
code: 200,
data: {
list: data,
total,
pageSize,
pageNum
}
}
} catch (error) {
ctx.body = { message: error, code: -1 }
}
})
return app.serve()
}
在云托管權限控制臺添加接口權限

開啟 api.poetries.top 本地調試服務

通過微信服務器模擬小程序請求


也可以在小程序中訪問

云托管內調用服務端獲取小程序碼接口
在代碼routes/home中添加
// 云托管內獲取小程序碼
router.get('/getweappCode', async (ctx, next) => {
let ACCESS_TOKEN = ''
let buffer = await rp({
method: 'POST',
// 在云托管容器環(huán)境中,可以拿到access_token,而且免鑒權、這里不需要填寫
// https://developers.weixin.qq.com/miniprogram/dev/wxcloudrun/src/guide/weixin/open.html
// 這里填http協(xié)議、在云托管中不需要填access_token、需要在云托管-云調用中填寫接口白名單前綴、開啟側邊欄proxy代理后可以免輸入本地調試
uri: `http://api.weixin.qq.com/wxa/getwxacode`,
body: {
path: '/pages/article/index'
},
json: true
}).catch(error=>{
ctx.body = {
code: -1,
message: error
}
throw error
})
ctx.body = {
data: buffer,
code: 200
}
})
在云托管權限控制臺添加接口權限

開啟 api.poetries.top 本地調試服務

通過微信服務器模擬小程序請求

也可以在小程序中訪問
