[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

劉嘉一發表於2018-03-08

無論你是 Node.js 的職業開發者,亦或是使用 Node.js 開發過 API 的普通開發者,你都極有可能使用了 Express.js。Express 可以稱得上是 Node.js 中最流行的框架了。

構建 Express App 極為容易。你僅需新增一些路由規則和對應的處理函式,一個簡單的應用就此誕生。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:一個使用傳統託管方法的簡單 Express.js App —— 響應單次請求的過程。

下列程式碼展示了一個最簡單的 Express App:

'use strict'

const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello world!'))

const port = process.env.PORT || 3000
app.listen(port, () => 
  console.log(`Server is listening on port ${port}.`)
)
複製程式碼

如果將上面的程式碼片段儲存為 app.js,那麼再需三步你就可以讓這個簡單的 Express App 執行起來。

  1. 首先將終端的工作目錄切換到 app.js 所在的資料夾,之後執行 npm init -y 命令以初始化一個新的 Node.js 專案。
  2. 使用終端執行 npm install express --save 命令以從 NPM 安裝 Express 模組。
  3. 執行 node app.js 命令,終端會回顯 “Server is listening on port 3000.” 字樣。

瞧,這就完成了一個 Express App。若使用瀏覽器訪問 http://localhost:3000,你便可以在開啟的網頁中看到 “Hello world!” 資訊。

應用部署

麻煩的問題來了:如何才能將你構建的 Express App 展示給你的朋友或者家人?如何才能讓每個人都能訪問到它?

應用部署是一個耗時且痛苦的過程,但現在我們就假定你已經很快、很好地完成了部署的工作。你的應用已經能被所有人訪問了,並且之後也運轉良好。

就這樣直到一天,突然有一大批使用者湧入開始使用你的應用。

你的伺服器開始變得疲憊不堪,不過仍然還能工作。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:一個使用傳統託管方法的簡單 Express.js App —— 處於較大負載下。

就這樣持續了一段時間後,它終於當機了。☠️

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:一個使用傳統託管方法的簡單 Express.js App —— 因為過多使用者訪問導致應用掛掉。

一大批使用者因為應用無法訪問而變得不開心(無論他們是否為此應用付費)。你對此感到絕望,並開始在 Google 上尋求解決方法。如果在雲(Cloud)上部署可以改善現狀嗎?

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:在雲上部署應該就可以解決應用規模伸縮的問題了,對吧?

此時你遇到了之前一個惱人的朋友,她又在給你談論 Serverless(無伺服器)技術的種種。但是等等,你現在可是有一臺伺服器的呀。雖然這臺伺服器是某個服務商提供的,並且它的狀態也不怎麼好暫時失去了控制,但總歸是能供你使用的。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:但是,Serverless 背後還是有一堆伺服器呀!

走投無路的你願意嘗試一切方法 ”挽救“ 你的應用,管它是 Serverless 還是其他什麼黑魔法。“不過,這個 Serverless 究竟是個什麼東西呢?”

你翻閱了數個網頁,包括 “Serverless Apps with Node and Claudia.js” 這本書的 第一章試讀(由 Manning Publications Co. 出版)。

在這一章中,作者使用洗衣機類比說明了 Serverless 的原理,這聽起來很瘋狂不過解釋起原理來還蠻有用。你的應用已經到了 ? 燒眉毛的地步了,因此你決定馬上試試 Serverless。

讓你的 Express.js App Serverless 化

上面書中的一整章都是基於 AWS 的 Serverless 進行編寫的。你已經知道了 Serverless API 是由 API Gateway 和 AWS Lambda function 組成的。現在需要考慮的是如何讓你的 Express App Serveless 化。

就像 Matt Damon 出演的電影《縮小人生》中描繪的橋段,Serverless 在未來也具有無限的潛力和可能性。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:如何才能讓你的 Express.js App 無縫接入 AWS Lambda?

Claudia 有能力幫助你把你的 App 部署到 AWS Lambda — 讓我們向它請教一番!

在執行 Claudia 命令前,請確保你已經參照 教程 配置好了 AWS 的訪問憑證。

為了能接入 AWS Lambda 和使用 Claudia 進行部署,你的程式碼需要稍微調整一下。你需要 export 你的 app,而不是呼叫 app.listen 去啟動它。你的 app.js 內容應該類似下列程式碼:

'use strict'

const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello world!'))

module.exports = app
複製程式碼

這樣修改後你可能無法在本地啟動 Express 伺服器了,不過你可以通過額外新增 app.local.js 檔案進行解決:

'use strict'

const app = require('./app')

const port = process.env.PORT || 3000
app.listen(port, () => 
  console.log(`Server is listening on port ${port}.`)
)
複製程式碼

之後想啟動本地伺服器執行下面的命令就可以了:

node app.local.js
複製程式碼

為了將你的應用正確接入 AWS Lambda,你還需要編寫一些程式碼將你的 Express App ”包裹“ 一番。在 Claudia 的幫助下,你只需要在終端中執行一條命令就可以生成 AWS Lambda 需要的 ”包裹“ 程式碼了:

claudia generate-serverless-express-proxy --express-module app
複製程式碼

命令結尾處的 app 指明瞭 Express App 的入口檔名,這裡無需附加 .js 副檔名。

這一步會生成 lambda.js 檔案,它的內容如下:

'use strict'
const awsServerlessExpress = require('aws-serverless-express')
const app = require('./app')
const binaryMimeTypes = [
  'application/octet-stream',
  'font/eot',
  'font/opentype',
  'font/otf',
  'image/jpeg',
  'image/png',
  'image/svg+xml'
]
const server = awsServerlessExpress
  .createServer(app, null, binaryMimeTypes)
exports.handler = (event, context) =>
  awsServerlessExpress.proxy(server, event, context
)
複製程式碼

至此已經完成了所有的準備工作!接下來你只需要執行 claudia create 命令就可以將你的 Express App(含 lambda.js 檔案)部署到 AWS Lambda 和 API Gateway 了。

claudia create --handler lambda.handler --deploy-proxy-api --region eu-central-1
複製程式碼

等待上述命令執行完成後,終端會輸出類似下面的響應資訊:

{
  "lambda": {
    "role": "awesome-serverless-expressjs-app-executor",
    "name": "awesome-serverless-expressjs-app",
    "region": "eu-central-1"
  },
  "api": {
    "id": "iltfb5bke3",
    "url": "https://iltfb5bke3.execute-api.eu-central-1.amazonaws.com/latest"
  }
}
複製程式碼

在瀏覽器中開啟響應資訊中返回的連結,若網頁展示出 “Hello world!” 那麼證明應用已經成功部署起來了!?

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:Serverless Express App。

將你的應用 Serverless 化後,你不再畏懼使用者群體的進一步擴大,應用會始終保持為可用狀態。

這並不是言過其實,因為在預設情況下 AWS Lambda 可通過彈性伸縮最高支援 1000 個 function 併發執行。當 API Gateway 接收到請求後,新的 function 會在短時間內處於可用狀態。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:在高負載下的 Serverless Express.js App。

這並不是你接入 Serverless 後唯一的收益。在保證應用不會因為高負載當機的前提下,你同樣削減了不少應用的執行開銷。使用 AWS Lambda,你僅需按你應用的實際訪問量付費。同樣,AWS 的免費試用計劃還將給予你每應用每月一百萬的免費流量(按訪問次數計算)。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:你的 Serverless App 真是太替你省錢了!

想了解更多關於使用 Serverless 帶來的好處,請點選檢視 這篇 文章。

Serverless Express.js App 的短板

即便 Serverless Express App 聽起來超讚,卻同樣有它的不足之處。

[譯] Express.js 與 AWS Lambda — 一場關於 serverless 的愛情故事

圖注:Serverless,”閹割“ 版。

下面是 Serverless Express App 一些最 “致命” 的短板:

  • Websockets 無法在 AWS Lambda 中使用。這是因為在 AWS Lambda 中,若應用沒有任何的訪問,那麼你的伺服器在客觀上也是不存在的。AWS IOT websockets over MQTT protocol 可以提供一個 “閹割” 版的 Websockets 支援。
  • 上傳 檔案到檔案系統同樣是無法工作的,除非你的上傳目錄是 /tmp 資料夾。這是因為 AWS Lambda function 對檔案系統是隻讀的,即使你將檔案上傳到了 /tmp 資料夾,它們也只會在 function 處於 “工作態” 時存在。為確保你應用中的上傳功能運轉正常,你應當把檔案上傳並儲存到 AWS S3 上。
  • 執行限制 也將影響你的 Serverless Express App 功能。例如 API Gateway 有 30 秒的超時時間限制,AWS Lambda 最大執行時間不能超過 5 分鐘等。

這僅僅算是你的應用與 AWS Lambda 之間關於 Serverless 愛情故事的一個序章,期待儘快湧現更多的愛情故事!

如往常一樣,感謝來自我的朋友 Aleksandar Simović 以及 Milovan Jovičić 的幫助和對文章的反饋意見。

所有的插圖均是使用 SimpleDiagrams4 創作的。

如果你想了解更多關於 Serverless Express 和 Serverless App 的資訊,“Serverless Apps with Node and Claudia.js” 這本書不容錯過。這本書由我和 Aleksandar Simovic 合作完成,Manning Publications 負責出版:

這本書除了會包含不少 Serverless Express App 的知識,它還將教會你如何使用 Node 和 Claudia.js 去構建、除錯真實場景下的 Serverless API(含 DB 和身份校驗)。隨書還將講解如何構建 Facebook Messenger 和簡訊(使用 Twilio)的聊天機器人,以及如何構建亞馬遜的 Alexa skills。

再次向 Aleksandar Simovic 表示衷心的感謝。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章