用户
搜索
  • TA的每日心情
    无聊
    3 小时前
  • 签到天数: 27 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    4

    主题

    15

    帖子

    441

    魔法币
    收听
    0
    粉丝
    1
    注册时间
    2017-6-5

    i春秋签约作者

    发表于 2018-1-8 21:09:32 175642

    0x00 前言

    最近有个项目中有要用到短域名服务的需求,于是去网上看了不少,可悲的是总有各种各样的小问题:

    所以最后还是决定自己写一个,哈哈。

    0x01 Demo

    话不多说,先上成品地址:http://tolnk.cn/ 源码会在文后打包送出。dalao们下手轻点,小服务器扛不住。

    0x02 分析

    1.接口

    通过调研分析市面上的大部分短网址服务,大致可判断出服务需要的一些接口:

    • 输入页面,服务提供的网页
    • 生成接口,通过传入长url参数,返回计算后的短url地址
    • 跳转接口,真正提供短域名的入口。通过生成的短url跳转到对应的长url
      上面就是一个短域名服务应该实际提供的东西了。当然,最后的最后,真正重要的一点,你要有一个短域名才行阿哈哈哈哈

      不过由于家中贫苦,最后本人只能搞到 tolnk.cn这么个稍微看的过去的域名了。。。
    2.功能

    光有接口,我们还要再想想具体的功能应该是什么样子的:
    通过网上的分析,一般现在的短网址算法的套路都是通过计算一个长域名的hash,通常使用crc32算法,然后把结果编码成62进制,然后把62进制字符串当作短网址。

    这里主要的就是这个hash算法。由于把大量的字符串映射到一个较小范围的字符串后,一般没有能力进行逆向运算,最直观的就是md5算法。因为只是取原文本的一个摘要,计算过程中肯定是会丢弃一些内容的。这也是为什么hash算法不能当作压缩算法的原理。(要是hash能逆运算,那世界上所有的数据都会用一小段hash去表示,那么空间也就失去了意义,这是不现实的)所以这势必会造成一定的碰撞。

    那么既然碰撞必然会发生,那么我们就尽量让它发生的概率小一点就可以了。这里我采用murmur64算法来进行hash运算。Go语言的一个实现地址在https://github.com/spaolacci/murmur3

    62进制:通常由[A-Za-z0-9]组成。由于murmur64算出来的hash其实是数字,那么我们需要尽可能简化这串数字的表达,因为这样会进一步缩短我们网址的长度,使用62进制可以基本满足我们的需求。

    3.存储

    由于短网址类似一个一对一的存储对象,类比成key:value的形式,很适合使用redis这类的系统。不过这里图方便,直接使用go语言的map来实现一个内存中的键值对存储功能。当然,后续会改成redis的。

    0x03 设计

    上面分析完了,下面我们就可以实际设计下整个项目了。
    这里我使用了go语言进行开发,主要是看中了它的跨平台编译能力,以及最后只需要分发一个二进制程序的特点。
    然后web框架我选择了gin。其实go自带的net/http已经可以做很多事情了,使用框架基本就是为了编写方便(当然还有我懒:))。
    对于接口,其实主要只有生成和跳转两个。为了不再这里费功夫讨论,我照搬了百度短网址服务 http://dwz.cn/ 提供的接口来设计。所以,最后我们的服务要提供的几个endpoint就长下面这样:

    • tolnk.cn/create.php,param:url,这里我设计传入的url是base64编码后的文件,免得自己再去进行url编码了。
    • token.cn/XXX,真正提供短链接的跳转地址。XXX是通过长网址生成的短网址crc结果的62进制字符串
    • tolnk.cn,根目录提供一个简单的html页面。光有接口,总不能让用户都去用postman之类的程序调用吧(>_<)

    这里主要说一下create接口的实现,我们的流程是这样的:接收传入的url参数,通过base64解码得到原始url,通过我们的计算函数得出短网址的62进制编码,然后构造返回值返回给用户。我们得到下面的流程图:

    当然中间还有什么判断url是否合法阿,以及数据库中是否已经存在此url等等一系列判断,这里就不明说了,有兴趣可以看源码。

    如此我们的main函数就可以写成下面这样:

    但是这样在编译时会出现问题:

    至于原因我现在还没有搞清楚,不过这并不能阻拦我们前进的动力。将/guid的接口改个名字,比如下面这样:

    编译通过后,可以通过搭建nginx代理重写url来达到我们目的!(是不是很聪明~快夸我快~)
    我们的重写规则是这样的(为了简单就没写那么严谨):

    跳转
    跳转这里很简单,图方便就一个301了事。写成代码就下面这样:

    0x04 编码

    这一步比较简单,大部分的代码我都在上一部分上图了,这里就略过。

    0x05 测试

    测试这一话,大家可以看我开篇提供的demo地址,如果有兴趣可以做些小测试。

    0x06 总结

    写到这,一个比较简单的短网址服务就出来了。其实这个东西从想法到实践,再到最后编码,也只用了一天不到。这期间了解了短网址服务的原理,以及顺手用了一下go的web框架:gin。就算是一次小小的练手项目吧。

    0x07 项目代码压缩包附在文末,练手项目写的比较渣,也没系统看过go,欢迎dalao们多提意见!

    如果大家有兴趣的话,也欢迎和我交流go语言的一些有趣的项目~


    游客,如果您要查看本帖隐藏内容请回复
    https://blog.scp500.com
    看看啊                  
    使用道具 举报 回复
    看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看
    使用道具 举报 回复
    看看看看看看看看看看看看看看看看看看看看
    使用道具 举报 回复
    发表于 2018-1-9 11:32:28
    顶楼主啦..希望楼主多发精品好帖啦.....
    欢迎加入i春秋QQ群大家庭,每人只能任选加入一个群哦!
    i春秋-楚:533191896
    i春秋-燕:129821314
    i春秋-齐:417360103
    i春秋-秦:262108018
    使用道具 举报 回复
    学习      
    使用道具 举报 回复
    无敌高大上的东西学习学习
    使用道具 举报 回复
    下载玩玩
    使用道具 举报 回复
    感谢楼主分享
    使用道具 举报 回复
    发表于 2018-1-9 15:42:56
    看看看看看看看看
    使用道具 举报 回复
    发表于 2018-1-10 10:15:22
    感谢分享,666
    使用道具 举报 回复
    发表于 2018-1-10 13:37:29
    感谢分享
    使用道具 举报 回复
    发表于 2018-1-10 13:45:02
    密码是什么啊
    使用道具 举报 回复
    有这个需求好久了,谢谢了
    使用道具 举报 回复
    发表于 2018-1-10 22:45:56
    1111111111111111
    http://www.imsunshine.cn/
    使用道具 举报 回复
    感谢楼主分享
    使用道具 举报 回复
    12下一页
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册