1. 程式人生 > >Serverless 架構應用開發指南:建立自己的 Serverless 短鏈服務

Serverless 架構應用開發指南:建立自己的 Serverless 短鏈服務

在想用 Serverless 可以做點什麼簡單的線上應用後,我想到了一個是線上短鏈生成服務。最後的結果見:http://x.pho.im/,一個非常簡單的線上應用。

因為上面的程式碼中,不能自動建立域名。然後,再針對資料庫進行了一些優化。

程式碼邏輯

這裡的程式碼邏輯比如簡單:

  • 建立短鏈時,使用生成一個四位的字串
  • 將原有的 URL 和生成的 URL 儲存到 DynamoDB 中
  • 在返回的 HTML 中,輸出對應的 URL
  • 重定向時,從 DynamoDB 讀取對應的短鏈
  • 如果短鏈存在,則執行 302 重定向;如果不存在,則返回一個 404。

建立首頁

首頁只是一個簡單的 HTML 表單:

const base_page = `<html>
<h1>Hi!</h1>
  <form method="POST" action="">
    <label for="uri">Link:</label>
    <input type="text" id="link" name="link" size="40" autofocus />
    <br/>
    <br/>
    <input type="submit" value="Shorten it!" />
  </form
>
</html>` module.exports.handler = (event, context, callback) => { console.log(JSON.stringify(event)); callback( null, { statusCode: 200, body: base_page, headers: {'Content-Type': 'text/html'}, } ); }

當我們提交的時候,就會觸發對應的 POST 請求。

生成短鏈

如上所述,對於個短鏈請求,我們要做這麼幾件事:

  1. 解析出提交表單中的連結
  2. 根據 URL 生成對應的短鏈
  3. 將對應的 URL 和短鏈的對應關係儲存到 DynamoDB 中
  4. 如果成功,則返回生成的短鏈;失敗則,返回一個 400

事實上,在儲存 URL 和短鏈的 map 之前,我們應該先判斷一下資料中是否已經有相應的短鏈。不過,對於這種只針對於我一個使用者的短鏈服務來說,這個步驟有點浪費錢——畢竟要去掃描一遍資料庫。所以,我也不想去新增這樣的擴充套件功能。

接下來,讓我們回到程式碼中去,程式碼的主要邏輯都是在 Promise 裡,按順序往下執行。

解析出提交表單中的連結

首先,我們通過 querystring 庫來解決中表單中的連結。

const submitted = querystring.parse(event.body).link;

根據 URL 生成對應的短鏈

接著,使用 Node.js 中的 crypto.randomBytes 方法來生成八位的偽隨機碼。

crypto.randomBytes(8)
  .toString('base64')
  .replace(/[=+/]/g, '')
  .substring(0, 4)

由於生成的偽隨機碼是 Buffer 型別,因此需要轉換為字串。同時,因為生成的短鏈中不應該有 “=+/”,它會導致生成的 URL 有異常。於是,我們便替換掉偽隨機碼中的這些特殊字型。最後,擷取生成的字串的前 4 位。

現在,我們就可以將其儲存到資料中了。

儲存到 Dynamo 資料庫中。

對應的儲存邏輯如下所示,我們 new 了一個 DocumentClient 物件,然後直接儲存到資料庫中。put 函式中的物件,即是對應的引數。

return docClient.put({
  TableName: tableName,
  Item: {
    slug: slug,
    url: submitted
  },
  Expected: {
    url: {Exists: false}
  }
}).promise().then(() => { return slug; });

最後,我們返回了 slug,用於接下來的處理。

返回短鏈給使用者

一切處理正常的話,我們將向用戶返回最後的內容:

return callback(
  null,
  {
    statusCode: 200,
    body: RenderPage(path.join(prefix, slug).replace(':/', '://'), prefix),
    headers: {'Content-Type': 'text/html'}
  }
);

其中的 HTML 部分的渲染邏輯如下所示:

function RenderPage (link, submitted) {
  return `
<html>
<body>
<h3>
  <a href="${link}">${link}</a>
</h3>
<p>URL ${submitted} was shortened to:
  <a href="${link}">${link}</a>
</p>
</body>
</html>`
};

是的,只是返回短鏈和原有的連結了。

好了,現在我們已經擁有這個短鏈了。接下來,就是點選這個短鏈,看看背後會發生些什麼?

重定向短鏈

首先,我們先在我們的 serverless.yml 中,將短鏈的路徑配置為引數:

functions :
  ...
  redirect:
    handler: redirect/index.handler
    events:
      - http:
          path: /{slug}
          method: get

然後,從資料庫中按短鏈的 slug 查詢對應的 URL:

const slug = event.pathParameters.slug;

docClient.get({
  TableName: tableName,
  Key: {
    slug: slug
  }
}, (err, data) => {

})

如果存在對應的短鏈,則 302 重定向對原有的 URL:

const item = data.Item;

if (item && item.url) {
  callback(
    null,
    {
      statusCode: 302,
      body: item.url,
      headers: {
        'Location': item.url,
        'Content-Type': 'text/plain'
      }
    }
  )
}

如果沒有,則返回一個 404。

我們的程式碼就是這麼的簡單,現在讓我們來部署測試一下。

部署及測試短鏈服務

如果你還沒有 clone 程式碼的話,執行下面的命令來安裝:

serverless install -u https://github.com/phodal/serverless-guide/tree/master/url-shorter -n url-shorter

然後執行 yarn install 來安裝對應的依賴。

如果你在 Route53 上註冊有相應的域名,修改一下 serverless.yml 檔案中的域名,我們就可以使用 serverless create_domain 來建立域名的路由。

緊接著,執行 serverless deploy 來部署。

api keys:
  None
endpoints:
  GET - https://4rr5ndhaw3.execute-api.us-east-1.amazonaws.com/dev/
  POST - https://4rr5ndhaw3.execute-api.us-east-1.amazonaws.com/dev/
  GET - https://4rr5ndhaw3.execute-api.us-east-1.amazonaws.com/dev/{slug}
functions:
  main: url-shorter-dev-main
  create: url-shorter-dev-create
  redirect: url-shorter-dev-redirect
Serverless Domain Manager Summary
Domain Name
  x.pho.im
Distribution Domain Name
  d2s4y0p5nuw3k7.cloudfront.net
Serverless: Removing old service versions...

一切準備就緒了。

Done!