聊聊关于短链接那些事


前言
最近在做一套推广系统,将其中涉及的 长短链接问题 在这里分享一下。推广方式主要是以短信方式慰问客户并推送宣传链接(非广告),但链接真的是太长了,先不说短信按字数收费问题,就是看到就想立刻删除。所以组织就安排研究如何让链接变短,精简干练。。。

关于长短链接

长链接 :顾名思义,就是网页的完整URL地址,点击即可跳转至网页,进行内容浏览。

短链接 :就是将长链接进行处理后转换成长度较小的URL地址,如 https://u5p.cn/upNbxj  则是长链接  https://blog.csdn.net/qq_39486758/article/details/126602389  处理之后的结 果。

短链接相较于长链接,会更简短,便于一些第三方平台的字符长度限制等问题处理,当然对于小编来说,可以省下不少短信费用,能不能“升官发财”就靠它了~~

长短链接原理
当我们在网站输入 短链接 后, DNS 会解析链接的ip地址(即 短链接服务器 ),然后DNS转发请求( HTTP GET )至短链接服务器,通过短链接码换取对应的 完整URL地址 ,最后短链接服务器通过请求( HTTP 301 )重定向到完整URL地址,至此完成解析。可以参考时序图:



注:短链接跳转长链接可以采用301(永久重定向),也可以采用302(临时重定向),区别就是对资源的管理,301会将旧资源永久移除,替换为重定向的新资源;而302还是会保留旧资源,只是重定向到新资源,并不会发生替换,也不会保存新资源。

演示案例
免费的在线工具 :

站长之家: https://tool.chinaz.com/tools/dwz.aspx,需要注册才能使用 ,毕竟是白嫖的,还是得尊重下~~

短网址:https://u5p.cn/,其中提供了设置有效期,访问密码等非常完善的功能,使用便捷

自研短链接服务 :由于开源项目存在不确定性,不得不自己搭建一套短链接服务,满足使用需求。一是便于维护,二是可以灵活扩展。接下来结合代码进行分析。

首先是生成短链接码的算法工具类,算法不是固定的,可以根据自己习惯或工作要求使用其它的算法生成,最主要是保证短链接码的唯一性。

 
 /**  
 
  * 进制转换工具  
 
  */  
 
 public   class   BaseUtil  { 
 
 
 
 // 62进制转换率  
 
 private  static  int  SCALE_62 = 62 ; 
 
 // 62进制,索引位置代表转换字符的数值 0-61,比如 A代表10,z代表61  
 
 private  static  String CHARS_62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ; 
 
 /**  
 
      * 十进制数字转换为62进制字符串  
 
  * @param value 十进制数字  
 
  * @return 62进制字符串  
 
  */  
 
  public  static  String encode10to62 (  long  value  )  { 
 
 if  ( value  < 0 ) { 
 
 throw  new  IllegalArgumentException( "参数非法(必须为非负数): "  + value ); 
 
 } 
 
 StringBuilder stringBuilder = new  StringBuilder(); 
 
 while  ( value  > SCALE_62 - 1 ) { 
 
 stringBuilder.append(CHARS_62.charAt(( int ) ( value  % SCALE_62))); 
 
 value  = value  / SCALE_62; 
 
 } 
 
 // 获取最高位  
 
 stringBuilder.append(CHARS_62.charAt(( int ) ( value  % SCALE_62))); 
 
 return  stringBuilder.reverse().toString(); 
 
    } 
 
 
 
 /**  
 
  * 将10进制数字转换为长度为length的62进制字符串  
 
      * 原始62进制字符串长度小于length,左侧用‘0’填充补齐  
 
 
 
  * @param value  十进制数字  
 
  * @param length 长度  
 
  * @return 长度为length或大于length的62进制字符串  
 
  */  
 
  public  static  String encode10to62 (  long  value , int  length )  { 
 
 if  (length  < 1 ) { 
 
 throw  new  IllegalArgumentException( "参数非法(长度必须大于0): "  + value ); 
 
 } 
 
 String str62Base = encode10to62( value ); 
 
 if  (str62Base.length()  < length) { 
 
 long  num = ( long ) Math.pow( 10 , length); 
 
 str62Base = num + str62Base; 
 
 str62Base = str62Base.substring(str62Base.length() - length); 
 
 } 
 
 return  str62Base; 
 
 } 
 
 /**  
 
      * 62进制编码转换为10进制编码  
 
 
 
  * @param str62Base 62进制编码  
 
  * @return 十进制编码  
 
  */  
 
  public  static  long  encode62to10 ( String str62Base )  { 
 
 if  (str62Base == null  || !str62Base.matches( "[a-zA-Z\\d]+" )) { 
 
 throw  new  IllegalArgumentException( "参数非法(非62进制): "  + str62Base); 
 
 } 
 
 int  length = str62Base.length(); 
 
 long  value  = 0 ; 
 
 for  ( int  index = 0 ; index  < length; index++) { 
 
 value  = value  * SCALE_62 + base62To10(str62Base.charAt(index)); 
 
 } 
 
 return  value ; 
 
 } 
 
 /**  
 
      * 62进制字符转换成对应十进制表示  
 
 
 
  * @param base62 62进制  
 
  * @return 十进制  
 
  */  
 
  private  static  int  base62To10 (  char  base62 )  { 
 
 int  value  = base62; 
 
 // ‘0-9’  0-9  
 
 // ‘0’ ASCII字符代码表 十进制48  
 
 // ‘9’ ASCII字符代码表 十进制57  
 
 if  ( value  <= 57 ) value  = value  - 48 ; 
 
 // ‘A-Z’  10-35  
 
 // ‘A’ ASCII字符代码表 十进制65  
 
 // ‘Z’ ASCII字符代码表 十进制90  
 
 else  if  ( value  <= 90 ) value  = value  - 65  + 10 ; 
 
 // ‘a-z’  36-61  
 
 // ‘a’ ASCII字符代码表 十进制97  
 
 // ‘Z’ ASCII字符代码表 十进制122  
 
 else  value  = value  - 97  + 36 ; 
 
 return  value ; 
 
 } 
 

 
然后就是维护短链接的 关系映射 ,此处小编采用的是集合变量,建议采用Mysql等数据库将关系数据持久化,避免数据丢失,导致访问失败。

 
 /*  
 
  * 短链接服务器地址  根据自己实际场景替换  
 
  * */  
 
     private   String  domainName =  "http://192.168.0.76:8822" ; 
 
 
 
 /*  
 
  * 短链接与长链接映射关系集合  
 
  * */  
 
     private  Map String 
> urlMap =  
new 
 HashMap <>();  
 
 
 
 /**  
 
      * 长链接编码成短链接  
 
 
 
  * @param originUrl 原始链接(长链接)  
 
  * @return 短链接  
 
  */  
 
     public   String  encode( String  originUrl) { 
 
 
 
 long id = System.currentTimeMillis(); 
 
 String  code = BaseUtil.encode10to62(id, 5 ); 
 
 urlMap.put(id, originUrl); 
 
 return  domainName + "/redirect/"  + code; 
 
 } 
 
提供转发处理接口,本质就是访问短链接服务的接口,完成解析到重定向的处理,至此,短链接服务器完成使命(同时在处理过程中可以增加访问记录等埋点操作)。

 
 /**  
 
  * 解码重定向  
 
  *  
 
  * @param url 原始链接的编码  
 
  * @return 重定向  
 
  */  
 
 @GetMapping ( "/redirect/{url}" ) 
 
 public  ModelAndView redirect( @PathVariable  String  url) { 
 
        long id = BasetUtil.encode62to10(smartUrl); 
 
 String  originUrl = urlMap.get(id); 
 
 RedirectView redirectView= new  RedirectView(originUrl); 
 
 // 301永久重定向,避免网络劫持  
 
 redirectView.setStatusCode(HttpStatus.MOVED_PERMANENTLY); 
 
 return  new  ModelAndView(redirectView); 
 
 } 
 
模拟操作过程:本地启动短链接服务,再启动一个业务服务作为长链接服务,将长链接生成短链接,然后访问短链接并成功跳转至长链接地址。演示结果

总结
以上就是本文所分享的全部内容,当然不止这一种实现方式,有想法的小伙伴可以私信探讨。

 
 
推荐阅读  
      ?  如何快速求出与n互素的数有多少个?      
 
    ?   躲不过设计模式的坑之代理模式     
 
    ?   匿名 iframe:COEP 的福音!     
 
    ?   为什么阿里巴巴禁止数据库中做多表join?     
 
    ?   阿里二面:RocketMQ 集群 Broker 挂了,会造成什么影响?     
 
    ?   这12款idea插件,能让你代码飞起来!     
 
    ?   如果把人的一生都记录到数据库里 ...