当前位置: 首页 > news >正文

【Golang】短链接系统

https://learnku.com/articles/73964
https://www.cnblogs.com/54chensongxia/p/11673522.html
https://www.cnblogs.com/Java3y/p/11976312.html
https://github.com/SnDragon/go-treasure-chest

经常在牛客上看到有短链接系统的项目

短链接是将原本冗长的URL做一次“包装”,变成一个简洁可读的URL。

为什么使用短链接

  • 节省发送的内容
    我们平时发微博或者短信是都是有最大字符限制的。如果你的一个URL太长,一个URL占用的字符数就已经超过了最大限制,根本发不出去。如果你细心观察过银行的信用卡中心给你发过来的活动短信的话,你会发现短信中的URL好多都是以短链接形式发送的。

  • 提升用户体验
    还是以上面的URL为列子。这一大串URL非常不美观,给人的感觉就是木马链接,用户可能都不会去点击。相反的,如果转换成http://url.cn/5MMEX3D,就非常易于阅读,看起来整洁干净,提高用户体验和点击率。

  • 便于链接追踪,分析点击来源
    通过短链接可以获知大部分用户的来源,和来源渠道的转化率、广告渠道的质量。通过渠道效果对比数据,更合理的进行广告投放和资源配置。

  • 同一个页面不同的链接
    每个用户需要推送带参数的唯一链接。

  • 一定程度上保护原始网站链接
    我们在玩Facebook,领英等社交时,有些需要分享一些带有我们网站链接的帖子和消息,尤其对于小白来说,如果发的内容次数过多,并且毫无互动可言或者直接被人举报多次,那么你的网址就会被社交平台标记,一旦标记,链接权重就会受影响,后面再投社交广告时就有麻烦了。

短链接生成原理

在这里插入图片描述

如http://url.cn/5MMEX3D这个短链接,当我们访问这个链接的时候我们先访问到url.cn对应的服务器,然后根据参数5MMEX3D找出它对应的原始连接,再重定向到这个原始链接上去。

比较著名的短链域名有腾讯的 url.cn,微博的 t.cn 等,也有很多公司提供了免费 / 收费的短链接开放 API

5MMEX3D和原始链接是如何进行映射的?

  • hash算法不行,这个场景是不能容许哈希碰撞的,一般不建议这么做

  • 发号器(ID自增)->再使用62进制编码。比如将https://github.com/ZhongFuCheng3y/3y这个长链接看作是10000,然后使用进制转换工具将10000进行62进制编码得到的结果是:2Bi,那么我们就可以得到一个短链接http://url.cn/2Bi。
    62进制转换是因为62进制转换后只含数字+小写+大写字母。而64进制转换会含有/,+这样的符号(不符合正常URL的字符)

短链接系统

代码来源于https://learnku.com/articles/73964
https://github.com/SnDragon/go-treasure-chest

使用 Redis 来生成自增 id,并存储映射关系

// Storage 短链服务抽象接口
type Storage interface {Shorten(url string, expSecond int64) (string, error)     // 将长链转成短链,并设置过期时间ShortLinkInfo(sid string) (*entity.UrlDetailInfo, error) // 根据短链id获取详情UnShorten(sid string) (string, error)                    // 根据短链id转成原始长链
}
// RedisStorage Redis实现短链服务
type RedisStorage struct {redisCli *redis.Client
}func (r *RedisStorage) Shorten(url string, expSecond int64) (string, error) {// 1. 获取自增idid, err := r.redisCli.Incr(RedisKeyUrlGlobalId).Result()if err != nil {return "", errors.Wrap(err, "[Shorten] incr global id err")}// 2. 转成base62(base64包含`+`、`/`字符,对URL不友好)sid := base62.EncodeInt64(Offset + id)// 3. 设置短url对应的原始urlif err := r.redisCli.Set(fmt.Sprintf(RedisKeyShortUrl, sid), url,time.Second*time.Duration(expSecond)).Err(); err != nil {return "", errors.Wrap(err, "[Shorten] set RedisKeyShortUrl err")}// 4. 设置详情urlDetail := &entity.UrlDetailInfo{OriginUrl: url,CreatedAt: time.Now().Unix(),ExpiredAt: time.Now().Unix() + expSecond,}if err := r.redisCli.Set(fmt.Sprintf(RedisKeyUrlDetail, sid),encoding.JsonMarshalString(urlDetail), 0).Err(); err != nil {return "", errors.Wrap(err, "[Shorten] set RedisKeyUrlDetail err")}return config.AppConfig.BaseUrl + sid, nil
}func (r *RedisStorage) ShortLinkInfo(sid string) (*entity.UrlDetailInfo, error) {// 1. 获取详情data, err := r.redisCli.Get(fmt.Sprintf(RedisKeyUrlDetail, sid)).Result()if err != nil {return nil, errors.Wrap(err, "[ShortLinkInfo] get url detail err")}// 2. 反序列化info := &entity.UrlDetailInfo{}if err := encoding.JsonUnMarshalString(data, info); err != nil {return nil, errors.Wrapf(err, "[ShortLinkInfo] JsonUnMarshalString err: %v", data)}// 3. 获取计数器countRet, err := r.redisCli.Get(fmt.Sprintf(RedisKeyUrlCounter, sid)).Result()if err == redis.Nil {countRet = "0"} else if err != nil {return nil, errors.Wrapf(err, "[ShortLinkInfo] get RedisKeyUrlCounter err, sid: %v", sid)}info.Counter = cast.ToInt64(countRet)return info, nil
}func (r *RedisStorage) UnShorten(sid string) (string, error) {// 1. 获取对应长链val, err := r.redisCli.Get(fmt.Sprintf(RedisKeyShortUrl, sid)).Result()if err == redis.Nil {return "", &serrors.StatusError{Code: http.StatusNotFound,Err:  fmt.Errorf("unknown url: %v", sid),}} else if err != nil {return "", errors.Wrap(err, "get RedisKeyShortUrl err")}// 2. 访问计数器+1if err := r.redisCli.Incr(fmt.Sprintf(RedisKeyUrlCounter, sid)).Err(); err != nil {// 只影响统计,不影响主流程,打印错误日志即可log.Printf("[UnShorten]Incr RedisKeyUrlCounter err, sid: %v\n", sid)}return val, nil
}

假设短链域名为 myurl.cn, 配置 host

127.0.0.1 myurl.cn

修改 configs/shorturl/app.yaml 的配置

base_url: http://myurl.cn/
redis_config:db_host: 127.0.0.1 db_port: 6379 db_passwd: db: 0

进入项目根目录启动服务

make run_short_url
go build -o build/shorturl ./cmd/shorturl  && ./build/shorturl

测试

curl -X POST \http://myurl.cn/api/shorten \-H 'cache-control: no-cache' \-H 'content-type: application/json' \-d '{"url":"https://www.baidu.com?name=SnDragon","expire_seconds":100}'返回
{"code": 0,"msg": "ok","short_url": "http://myurl.cn/4C99"
}

浏览器访问http://myurl.cn/4C99重定向到baidu

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • matlab中的双层数值积分
  • 这本vue3编译原理开源电子书,初中级前端竟然都能看懂
  • 3.插件化系列之动态加载class示例
  • OverlayFS 文件系统介绍
  • 聊聊《思考,快与慢》
  • Synthesia——虚拟人物视频生成
  • springboot校园商店配送系统-计算机毕业设计源码68448
  • 在AD中,‌如果原理图的元件跑到了图纸框之外,‌可以通过以下方法将其拉回图纸内
  • 数据合成的艺术:sklearn中的数据生成技术
  • 为 Laravel 提供生产模式下的容器化环境:打造现代开发环境的终极指南
  • go语言怎么把字符串都转化为小写?
  • 睿考网:CPA考试各科难度分析
  • 【数据结构与算法】算法(Algorithm)的基本概念与特性
  • C++第二十八弹---进一步理解模板:特化和分离编译
  • [opencv]opencv源码编译cmake所需缓存文件cache文件下载地址汇总
  • 自己简单写的 事件订阅机制
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • [译]前端离线指南(上)
  • 【技术性】Search知识
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CSS 专业技巧
  • extjs4学习之配置
  • Fundebug计费标准解释:事件数是如何定义的?
  • Git 使用集
  • Java 多线程编程之:notify 和 wait 用法
  • Java 最常见的 200+ 面试题:面试必备
  • Java小白进阶笔记(3)-初级面向对象
  • js写一个简单的选项卡
  • js正则,这点儿就够用了
  • Next.js之基础概念(二)
  • PHP那些事儿
  • React-flux杂记
  • use Google search engine
  • 彻底搞懂浏览器Event-loop
  • 记一次和乔布斯合作最难忘的经历
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 马上搞懂 GeoJSON
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 实习面试笔记
  • 使用SAX解析XML
  • 算法-插入排序
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 小而合理的前端理论:rscss和rsjs
  • 用mpvue开发微信小程序
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 阿里云ACE认证学习知识点梳理
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 说说我为什么看好Spring Cloud Alibaba
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • (1)Nginx简介和安装教程
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (NSDate) 时间 (time )比较
  • (附源码)计算机毕业设计ssm本地美食推荐平台