短链服务,短链生成

ca88会员登录中心

短链生成,链生成

 1  /// <summary>
 2  /// 短链生成
 3  /// </summary>
 4  public class ShortUrlBuilder
 5         {
 6             private static readonly string[] Chars = 
 7             { "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h" ,
 8 
 9             "i" , "j" , "k" , "l" , "m" , "n" , "o" , "p" , "q" , "r" , "s" , "t" ,
10 
11             "u" , "v" , "w" , "x" , "y" , "z" , "0" , "1" , "2" , "3" , "4" , "5" ,
12 
13             "6" , "7" , "8" , "9" , "A" , "B" , "C" , "D" , "E" , "F" , "G" , "H" ,
14 
15             "I" , "J" , "K" , "L" , "M" , "N" , "O" , "P" , "Q" , "R" , "S" , "T" ,
16 
17             "U" , "V" , "W" , "X" , "Y" , "Z"
18             };
19 
20             /// <summary>
21             /// 生成指定URL的摘要
22             /// </summary>
23             /// <param name="url">URL</param>
24             /// <returns>短链列表,任取一个存储就行。</returns>
25             public static List<string> Build(string url)
26             {
27                 var shortUrls = new List<string>();
28                 if (url == null)
29                 {
30                     return shortUrls;
31                 }
32                 var hash = GetMd5(url);
33                 //将32个字符的md5码分成4段处理,每段8个字符
34                 for (int i = 0; i < 4; i++)
35                 {
36 
37                     int offset = i * 8;
38 
39                     string sub = hash.Substring(offset,   8);
40 
41                     long sub16 = long.Parse(sub, NumberStyles.HexNumber); //将sub当作一个16进制的数,转成long
42 
43                     // & 0X3FFFFFFF,去掉最前面的2位,只留下30位
44                     sub16 &= 0X3FFFFFFF;
45 
46                     StringBuilder sb = new StringBuilder();
47                     //将剩下的30位分6段处理,每段5位
48                     for (int j = 0; j < 6; j++)
49                     {
50                         //得到一个 <= 61的数字
51                         long t = sub16 & 0x0000003D;
52                         sb.Append(Chars[(int)t]);
53 
54                         sub16 >>= 5;  //将sub16右移5位
55                     }
56 
57                     shortUrls.Add(sb.ToString());
58                 }
59                 return shortUrls;
60             }
61 
62             /// <summary>
63             /// MD5加密
64             /// </summary>
65             /// <param name="myString">原始字符串</param>
66             /// <param name="salt">盐</param>
67             /// <returns></returns>
68             private static string GetMd5(string myString, string salt = "")
69             {
70                 if (myString != null)
71                 {
72                     var array = myString.ToCharArray();
73                     Array.Reverse(array);
74                     myString = $"{new string(array)}+{{{salt}}}";
75 
76 #if DEBUG
77                     Debugger.Log(1, "2", $"自定义消息:{myString}\r\n");
78 #endif
79                     MD5 md5 = MD5.Create();
80                     byte[] bs = Encoding.UTF8.GetBytes(myString);
81                     byte[] hs = md5.ComputeHash(bs);
82                     StringBuilder sb = new StringBuilder();
83                     foreach (byte b in hs)
84                     {
85                         // 以十六进制格式格式化  
86                         sb.Append(b.ToString("x2"));
87                     }
88                     return sb.ToString();
89 
90                 }
91                 return null;
92             }
93         }

 

1 /// summary 2 /// 短链生成 3
/// /summary 4 public class ShortUrlBuilder 5 { 6 private static
readonly string [] Chars = 7 { ” a ” , ” b ” , ” c ” ,…

      
最近一段时间由于工作需要,仔细研读了微软企业库的部分源码,不由得佩服这些大洋彼岸的同行们.先不谈代码的架构怎么样,起码在代码注释这一块,那叫一个专业啊.一个200行的源文件150行注释50行代码是常有的事.注释量不仅多,质量也高.我的很多困惑都是通过阅读代码注释得以解答的.

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

      这年头,代码注释的方式基本都是采用以///开头的xml注释方式了.在visual
studio里,连续输入三个///,编辑器会自动补全剩下的部分.默认使用的是summary标签.如果是方法则可能还会有param与returns标签.这也是我们最常用到的三个标签.难道xml注释方式只有这三种标签吗?显然不是.当你再输入一个<的时候,编辑器就会自动提示还可以使用的标签.粗粗一算,整整20个,可真不少呀.

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

      上网查阅了一下,其实常用的只有11个标签左右,下面大概介绍一下

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

      summary,被注释对象的摘要

代码逻辑

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

  • 创建短链时,使用生成一个四位的字符串
  • 将原有的 URL 和生成的 URL 存储到 DynamoDB 中
  • 在返回的 HTML 中,输出对应的 URL
  • 重定向时,从 DynamoDB 读取对应的短链
  • 如果短链存在,则执行 302 重定向;如果不存在,则返回一个 404。

      example,展现被注释对象的一个示例

创建首页

首页只是一个简单的 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 请求。

      c,在注释中写代码,当代码只有一行的时候使用.通常与example配合使用

生成短链

如上所述,对于个短链请求,我们要做这么几件事:

  1. 解析出提交表单中的链接
  2. 根据 URL 生成对应的短链
  3. 将对应的 URL 和短链的对应关系存储到 DynamoDB 中
  4. 如果成功,则返回生成的短链;失败则,返回一个 400

事实上,在存储 URL 和短链的 map
之前,我们应该先判断一下数据中是否已经有相应的短链。不过,对于这种只针对于我一个用户的短链服务来说,这个步骤有点浪费钱——毕竟要去扫描一遍数据库。所以,我也不想去添加这样的扩展功能。

接下来,让我们回到代码中去,代码的主要逻辑都是在 Promise
里,按顺序往下执行。

      code,在注释中写代码,当代码有多行时使用.通常与example配合使用

解析出提交表单中的链接

首先,我们通过 querystring 库来解决中表单中的链接。

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

      param,被注释对像的参数,有一个name属性,指定注释哪一个参数

根据 URL 生成对应的短链

接着,使用 Node.js 中的 crypto.randomBytes 方法来生成八位的伪随机码。

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

由于生成的伪随机码是 Buffer
类型,因此需要转换为字符串。同时,因为生成的短链中不应该有
“=+/”,它会导致生成的 URL
有异常。于是,我们便替换掉伪随机码中的这些特殊字体。最后,截取生成的字符串的前
4 位。

现在,我们就可以将其存储到数据中了。

      returns,被注释对像的返回值

存储到 Dynamo 数据库中。

对应的存储逻辑如下所示,我们 new 了一个 DocumentClient
对象,然后直接存储到数据库中。put 函数中的对象,即是对应的参数。

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

最后,我们返回了 slug,用于接下来的处理。

     
exception,被注释对象执行时可能抛出的异常.有一个cref属性,指定异常类型

返回短链给用户

一切处理正常的话,我们将向用户返回最后的内容:

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>`
};

是的,只是返回短链和原有的链接了。

好了,现在我们已经拥有这个短链了。接下来,就是点击这个短链,看看背后会发生些什么?

      remarks,被注释对象的备注.用来详细描述被注释对象

重定向短链

首先,我们先在我们的 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。

我们的代码就是这么的简单,现在让我们来部署测试一下。

      para,段落标签.
类似于HTML里的P标签.写在里面的内容会作为单独的一段

部署及测试短链服务

如果你还没有 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!

     
paramref,引用参数.在摘要,备注或其它地方如果要对参数进行说明,如果将参数以该标签包裹,最终生成的chm文档时会生成一个超键接指向该参数,有一个name属性,指定参数名称

      see,参考标签.有一个cref属性,指定参考类型名.

 

     
以上11个标签在使用上各不相同.首先,只有被summary包裹或param,returns,para这四个标签才能在visual
studio的智能感知里看到效果.你单独写一个remarks标签vs是感知不到的,其它的注释效果需要用工具生成chm后才能看到.其次,summary,example,returns,remarks,para会成普通文字格式,c,code会生成代码格式,exception,see会生成一个超链接链向指定类型.更加详细的说明可参考本文最后的链接.

 

      现在再来谈一谈注释生成工具的使用.最早的工具是微软的御用工具DocGen,开源的NDoc,还有一个通用工具DoxyGen,但是现在这几个要么不好用,生成的文档不符合.net习惯,要么软件停止更新了,不好获取了.现在用的比较多的是Sandcastle.个人体验了一下,效果不错!更加详细的说明可参考本文最后的链接.

      文章的最后还是放上一段个人比较喜爱的一句话,与君共勉:

 

     
傻瓜都可以写出机器能读懂的代码,但只有专业程序员才能写出人能读懂的代码

 

      参考的文章:

  1. C# and XML Source Code
    Documentation
  2. XML Comments Let You Build Documentation Directly From Your Visual
    Studio .NET Source
    Files

  3. Sandcastle—-强大的C#文档生成工具

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图