短链接你真的了解吗?

3,253 阅读4分钟

“这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

其实很多公司都会发送各种营销短信给用户,而且短信里面通常会带上各种活动链接,然后用户点开链接可以打开浏览器到活动页面。

截屏2022-01-23 下午9.42.59.png

发送短信的时候里面有个链接看到没?这就是短链接,然后我们把短链接复制到浏览器打开,发现跳转之后立马就换了个地址,而且链接还很长很长。先暂停一下,思考背后的原理是什么?

// 原地址
https://u.10010.cn/qAPZU

// 目标地址
'https://m.client.10010.com/mobileService/clickCountLogRecord/pageClickCount.htm?flag=new&title=礼包&openUrl=https://m.client.10010.com/myPrizeForActivity/tenth517/homePage&duanlianjieabc=qAPZU'

短链接跳转长链接,其实原理很简单,通过 302 临时重定向即可完成。

  1. 浏览器先向 u.10010.cn/qAPZU 地址发送 GET 请求。
  2. 根据参数 qAPZU 去查找数据库,找到对应的活动的真实链接。
  3. 后端返回了 302 重定向,并且指定了目标地址。
  4. 浏览器跳转到目标地址。

截屏2022-01-24 上午10.05.57.png

下面是用 node 代码简单实现一个重定向的功能。

const http = require('http')
const server = http.createServer()

// 这里存放所有的短链和长链的对应关系
const urlMap = {
  'qAPZU': 'https://m.client.10010.com/mobileService/clickCountLogRecord/pageClickCount.htm?flag=new&title=礼包&openUrl=https://m.client.10010.com/myPrizeForActivity/tenth517/homePage&duanlianjieabc=qAPZU'
}

server.on('request', function (req, res) {
  const pathname = req.url.slice(1)
  const taretUrl = urlMap[pathname]
  console.log(taretUrl)
  if (taretUrl) {
    // 通过响应头来实现服务端重定向
    res.writeHead(302, {
      'Location': encodeURI(taretUrl)
    })
    res.end()
  } else {
    res.end('404')
  }
})
server.listen(3000, function () { console.log('启用成功'); })

常见问题

如何实现长地址和短地址的对应关系呢?首先我们需要确保每次生成的短地址都是唯一的,因此我们很容易想到随机数,随机生成第一短地址,去查找是否用过,用过就再随机,如此往复,直到随机到一个没用过的短地址。

上面是典型的错误回答,下面咱们直接说正确的原理。正确的原理就是通过发号策略,给每一个过来的长地址,发一个号即可,小型系统直接用 mysql 的自增索引就搞定了。

https://u.10010.cn/1
https://u.10010.cn/2
...
https://u.10010.cn/999

其实生成的短链还有一个特点,就是不会直接用 10 进制表示,比如 u.10010.cn/999 这样的形式,而是把 999 转换为 62 进制表示,比如 u.10010.cn/g7 。其中 999 表示我发号策略参数唯一标识。

62进制是通过(数字 + 小写字母 + 大写字母)组合而成的。如果五个字符是(0-9)、(A-Z)、(a-z),那5位字符可以穷举多个呢?62^5 = 916132832个 如果6位呢?62^6 = 56800235584个 500多亿个网址。

微信防封禁

小程序提供的服务中,不得存在滥用分享违规行为。但是有时候我们只是普通的分享也有可能被微信封禁,脑瓜子嗡嗡的,无缘无故就被封封禁了。

假设我有两个页面,一个是首页,一个是活动页面。

{
  "pages": ["pages/index/index", "pages/activity/activity"]
}

当活动页面 pages/activity/activity 分享的时候,我们不是直接分享这个页面,而是分享首页 pages/index/index。但是直接到首页肯定是不行的呀,我们要加个参数标记一下 pages/index/index?channel=qAPZU

这个时候分享再打开我们发现有参数 channel=qAPZU,然后 API 后端会提供给我们一个解析参数的接口,后台通过查询数据库返回我们真实地址是 pages/activity/activity,最后我们跳转到目标页面。

这样一来每次打开的是首页,通常首页是不会封禁,然后才会跳转目标页面。

如果还是很担心首页被封禁,我们可以多准备几个首页就可以,比如一个是为营销活动做的首页,一个是正常的首页。

{
  "pages": ["pages/index/index", "pages/index2/index", "pages/activity/activity"]
}

我们选择备份的首页跳转 pages/index2/index?channel=qAPZU,如果 index2 封了不影响我们其他业务。

如果发现活动地址 pages/activity/activity 被封了怎么办?我们可以 channel=qAPZU 对应的地址改成另一个活动页面,如果你实在没有其他活动页面了,你就改成首页也行,防止用户在封禁过程中用户打开的是空白页面。

你可以打开某多多试一试,他们的活动也是先到首页再到目标活动页面

当然,站在巨人的肩膀上还是要按照规矩办事,必须遵守平台规则。