藉助騰訊雲的雲函數實現一個極簡的API網關
Intro
微信小程序的域名需要備案,但是沒有大陸的服務器,而且覺得備案有些繁瑣,起初做的小程序都有點想要放棄了,後來瞭解到騰訊雲的雲函數,於是利用騰訊雲的雲函數實現了一個簡單的 API 網關,通過雲函數來調用真正的 API 地址,藉此來繞過域名備案的問題。
雲函數簡介
騰訊云云函數(Serverless Cloud Function,SCF)是騰訊云爲企業和開發者們提供的無服務器執行環境,幫助您在無需購買和管理服務器的情況下運行代碼, 是實時文件處理和數據處理等場景下理想的計算平臺。 您只需使用 SCF 平臺支持的語言編寫核心代碼並設置代碼運行的條件,即可在騰訊雲基礎設施上彈性、安全地運行代碼。
計算資源的變遷
隨着雲服務的發展,計算資源高度抽象化,騰訊雲提供了從物理服務器到雲函數和橫跨各種抽象程度的計算資源供用戶選擇。
- 黑石物理服務器:以物理機爲擴展單位。用戶完全擁有整臺實體計算資源,安全性最好。
- 雲服務器(CVM):以雲服務器爲擴展單位,虛擬化硬件設備。用戶和其他租戶共享物理機資源,仍可自行配置 CVM 的各項指標,相對部署和迭代更加簡單。
- 容器:以服務爲擴展單位,虛擬化操作系統。測試和生產環境完全一致,測試和部署非常輕鬆。
- 雲函數:以函數爲擴展單位,虛擬化運行時環境(Runtime)。是現有計算資源的最小單位,具有完全自動、一鍵部署、高度可擴展等特點,是輕量級服務部署非常好的選擇。
無服務器的概述
無服務器(Serverless)不是表示沒有服務器,而表示當您在使用 Serverless 時,您無需關心底層資源,也無需登錄服務器和優化服務器,只需關注最核心的代碼片段,即可跳過複雜的、繁瑣的基本工作。核心的代碼片段完全由事件或者請求觸發,平臺根據請求自動平行調整服務資源。Serverless 擁有近乎無限的擴容能力,空閒時,不運行任何資源。代碼運行無狀態,可以輕易實現快速迭代、極速部署。
更多介紹參考官方文檔
騰訊雲函數目前有免費額度可以用,應用不大,基本可以夠用:
我的這個只是一個演示功能,免費的額度應該足夠了,選用最低的內存配置,運行一個月妥妥的沒問題,還會有剩餘時間。
60 * 60 * 24 * 31 = 2,678,400 < 3,200,000
創建雲函數
創建雲函數:
默認提供了一些模板,可以根據自己需要創建,我這裏選擇空白函數,選擇的運行環境是 nodejs 8.9,然後下一步即可
如果你的方法比較簡單可以直接編輯好再完成,如果比較複雜的話可以先完成,在本地編輯好再更新。
使用方式
- 更新雲函數
修改 index.ts
文件中的要轉發的地址
在該目錄下執行 tsc
,生成編譯後的 js
到 dist 目錄下執行 npm install
,安裝依賴,目前用到的只有一個 got
,如果用到了別的請在 package.json
文件裏添加,或者執行 npm install <package-name> --save
之後打包 dist 目錄下的內容到 zip,然後上傳到騰訊雲的控制檯即可
需要注意,壓縮包不能包含 dist 目錄,打開壓縮包之後就是代碼
dist.zip
- -- node_modules
- -- httpRequester.js
- -- index.js
- -- packages.json
- 配置觸發方式:
創建 API 網關觸發器之後會在 API 網關那邊創建一個服務,並且會得到一個訪問的地址
我們訪問下面的路徑就可以訪問到我們的 api 了,示例:
這個請求會實際轉發到 https://reservation.weihanli.xyz/api/notice
在小程序的請求接口地址使用這個地址就可以了,這樣就暫時繞過了小程序服務器域名備案~~
實現原理
請求轉發,實現一個簡單的 API 網關
實現過程中遇到的問題
unable to verify the first certificate
這個是 https 請求證書驗證的問題,參考 stackoverflow https://stackoverflow.com/questions/31673587/error-unable-to-verify-the-first-certificate-in-nodejs/32440021
通過設置了一個環境變量 NODE_TLS_REJECT_UNAUTHORIZED=0
來解決了
訪問 api 404
訪問之後,通過看日誌,輸出請求的地址發現,request 的 path 是帶函數名稱的,所以將函數名去掉就可以了
if ((<string>event.path).startsWith('/reservationWxAppGateway')) {
event.path = (<string>event.path).replace('/reservationWxAppGateway', '');
}
後來發現在 event
的參數裏有個 event.requestContext.path
來表示雲函數的 path,把這個 path 去掉就是真正請求的路徑
if((<string>event.path).startsWith(`${event.requestContext.path}`)){
event.path = (<string>event.path).replace(`${event.requestContext.path}`, '');
}
請求頭的轉發
請求頭轉發的時候, host
請求頭不能傳,我在傳遞 headers 的時候將 host
請求頭設置爲 undefined
headers["host"]= undefined;