在想用 Serverless 可以做點(diǎn)什么簡(jiǎn)單的在線應(yīng)用后,我想到了一個(gè)是在線短鏈生成服務(wù)骇陈。最后的結(jié)果見(jiàn):http://x.pho.im/你雌,一個(gè)非常簡(jiǎn)單的在線應(yīng)用婿崭。
這里的代碼基于:https://github.com/vannio/serverless-shrink氓栈。
因?yàn)樯厦娴拇a中授瘦,不能自動(dòng)創(chuàng)建域名提完。然后,再針對(duì)數(shù)據(jù)庫(kù)進(jìn)行了一些優(yōu)化挡篓。
代碼邏輯
這里的代碼邏輯比如簡(jiǎn)單:
- 創(chuàng)建短鏈時(shí)帚称,使用生成一個(gè)四位的字符串
- 將原有的 URL 和生成的 URL 存儲(chǔ)到 DynamoDB 中
- 在返回的 HTML 中闯睹,輸出對(duì)應(yīng)的 URL
- 重定向時(shí)楼吃,從 DynamoDB 讀取對(duì)應(yīng)的短鏈
- 如果短鏈存在妄讯,則執(zhí)行 302 重定向;如果不存在亥贸,則返回一個(gè) 404躬窜。
創(chuàng)建首頁(yè)
首頁(yè)只是一個(gè)簡(jiǎn)單的 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'},
}
);
}
當(dāng)我們提交的時(shí)候炕置,就會(huì)觸發(fā)對(duì)應(yīng)的 POST 請(qǐng)求荣挨。
生成短鏈
如上所述朴摊,對(duì)于個(gè)短鏈請(qǐng)求默垄,我們要做這么幾件事:
- 解析出提交表單中的鏈接
- 根據(jù) URL 生成對(duì)應(yīng)的短鏈
- 將對(duì)應(yīng)的 URL 和短鏈的對(duì)應(yīng)關(guān)系存儲(chǔ)到 DynamoDB 中
- 如果成功,則返回生成的短鏈甚纲;失敗則口锭,返回一個(gè) 400
事實(shí)上介杆,在存儲(chǔ) URL 和短鏈的 map 之前这溅,我們應(yīng)該先判斷一下數(shù)據(jù)中是否已經(jīng)有相應(yīng)的短鏈。不過(guò)莫其,對(duì)于這種只針對(duì)于我一個(gè)用戶(hù)的短鏈服務(wù)來(lái)說(shuō),這個(gè)步驟有點(diǎn)浪費(fèi)錢(qián)——畢竟要去掃描一遍數(shù)據(jù)庫(kù)乱陡。所以憨颠,我也不想去添加這樣的擴(kuò)展功能。
接下來(lái)积锅,讓我們回到代碼中去爽彤,代碼的主要邏輯都是在 Promise 里,按順序往下執(zhí)行缚陷。
解析出提交表單中的鏈接
首先适篙,我們通過(guò) querystring
庫(kù)來(lái)解決中表單中的鏈接。
const submitted = querystring.parse(event.body).link;
根據(jù) URL 生成對(duì)應(yīng)的短鏈
接著箫爷,使用 Node.js 中的 crypto.randomBytes
方法來(lái)生成八位的偽隨機(jī)碼嚷节。
crypto.randomBytes(8)
.toString('base64')
.replace(/[=+/]/g, '')
.substring(0, 4)
由于生成的偽隨機(jī)碼是 Buffer 類(lèi)型,因此需要轉(zhuǎn)換為字符串虎锚。同時(shí)硫痰,因?yàn)樯傻亩替溨胁粦?yīng)該有 "=+/",它會(huì)導(dǎo)致生成的 URL 有異常窜护。于是效斑,我們便替換掉偽隨機(jī)碼中的這些特殊字體。最后柄慰,截取生成的字符串的前 4 位鳍悠。
現(xiàn)在,我們就可以將其存儲(chǔ)到數(shù)據(jù)中了坐搔。
存儲(chǔ)到 Dynamo 數(shù)據(jù)庫(kù)中藏研。
對(duì)應(yīng)的存儲(chǔ)邏輯如下所示,我們 new 了一個(gè) DocumentClient 對(duì)象概行,然后直接存儲(chǔ)到數(shù)據(jù)庫(kù)中蠢挡。put
函數(shù)中的對(duì)象,即是對(duì)應(yīng)的參數(shù)凳忙。
return docClient.put({
TableName: tableName,
Item: {
slug: slug,
url: submitted
},
Expected: {
url: {Exists: false}
}
}).promise().then(() => { return slug; });
最后业踏,我們返回了 slug
,用于接下來(lái)的處理涧卵。
返回短鏈給用戶(hù)
一切處理正常的話勤家,我們將向用戶(hù)返回最后的內(nèi)容:
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>`
};
是的,只是返回短鏈和原有的鏈接了柳恐。
好了伐脖,現(xiàn)在我們已經(jīng)擁有這個(gè)短鏈了热幔。接下來(lái),就是點(diǎn)擊這個(gè)短鏈讼庇,看看背后會(huì)發(fā)生些什么绎巨?
重定向短鏈
首先,我們先在我們的 serverless.yml
中蠕啄,將短鏈的路徑配置為參數(shù):
functions :
...
redirect:
handler: redirect/index.handler
events:
- http:
path: /{slug}
method: get
然后场勤,從數(shù)據(jù)庫(kù)中按短鏈的 slug 查找對(duì)應(yīng)的 URL:
const slug = event.pathParameters.slug;
docClient.get({
TableName: tableName,
Key: {
slug: slug
}
}, (err, data) => {
})
如果存在對(duì)應(yīng)的短鏈,則 302 重定向?qū)υ械?URL:
const item = data.Item;
if (item && item.url) {
callback(
null,
{
statusCode: 302,
body: item.url,
headers: {
'Location': item.url,
'Content-Type': 'text/plain'
}
}
)
}
如果沒(méi)有歼跟,則返回一個(gè) 404和媳。
我們的代碼就是這么的簡(jiǎn)單,現(xiàn)在讓我們來(lái)部署測(cè)試一下嘹承。
部署及測(cè)試短鏈服務(wù)
如果你還沒(méi)有 clone 代碼的話窗价,執(zhí)行下面的命令來(lái)安裝:
serverless install -u https://github.com/phodal/serverless-guide/tree/master/url-shorter -n url-shorter
然后執(zhí)行 yarn install
來(lái)安裝對(duì)應(yīng)的依賴(lài)如庭。
如果你在 Route53 上注冊(cè)有相應(yīng)的域名叹卷,修改一下 serverless.yml
文件中的域名,我們就可以使用 serverless create_domain
來(lái)創(chuàng)建域名的路由坪它。
緊接著骤竹,執(zhí)行 serverless deploy
來(lái)部署。
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...
一切準(zhǔn)備就緒了往毡。
- 訪問(wèn) https://x.pho.im/
- 然后輸入一個(gè)鏈接蒙揣,如:https://github.com/phodal/serverless-guide
- 復(fù)制生成的地址:https://x.pho.im/rgQC,并返回
- 看是否會(huì)重定向到我們的網(wǎng)站上开瞭。
Done!