Serverless 架构应用开发指南:创建自己的 Serverless 短链服务

在想用 Serverless 可以做点什么简单的在线应用后,我想到了一个是在线短链生成服务。最后的结果见:http://x.pho.im/,一个非常简单的在线应用。

这里的代码基于:https://github.com/vannio/serverless-shrink

因为上面的代码中,不能自动创建域名。然后,再针对数据库进行了一些优化。

代码逻辑

这里的代码逻辑比如简单:

  • 创建短链时,使用生成一个四位的字符串
  • 将原有的 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...

一切准备就绪了。

  1. 访问 https://x.pho.im/
  2. 然后输入一个链接,如:https://github.com/phodal/serverless-guide
  3. 复制生成的地址:https://x.pho.im/rgQC,并返回
  4. 看是否会重定向到我们的网站上。

Done!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,590评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,407评论 25 707
  • 本文是GitChat《Serverless 风格微服务的持续交付(上):架构案例》部分内容已做修改。文章聊天实录请...
    顾宇阅读 3,189评论 1 13
  • 高考那年有作文题目是拒绝平庸,但生活中往往是甘于平庸。谚语,枪打出头鸟。正好说明了这个道理,比如上学的时候,我父母...
    社会我梦妮阅读 624评论 0 0
  • 阴山多宝,世人皆知,所以来阴山的人不胜枚举。 一日,阴山来了位俊俏少年,来阴山的人只有一个目的,寻宝。这少年也不例...
    袭姝Liner阅读 367评论 0 0