扫描二维码 上传二维码
域名商店
选择防红平台类型,避免链接被拦截
选择允许访问的平台类型

缩短链接

不知道你有没有留意过,微博上那些"t.cn"开头的链接,或者短信里短短一串字符的网址——点进去之后,却会跳到一个拖着一大串参数的原始地址。这背后就是链接缩短服务在做的事:把冗长的URL映射成几个字符的短码(比如 a1b2c),用户访问短链时,服务器再通过重定向把他送到真正的目的地。

为什么要多绕这一步?理由很实际。社交媒体和短信对字符数卡得很死,一个带满参数的链接动辄上百个字符,直接吃掉大半篇幅;换成短链,既省地方又看着清爽。更重要的是,短链服务还能顺手做不少事:统计点击量、设置有效期、隐藏原始参数……这些附加价值,让它在营销和运营场景里几乎成了标配。



整个流程拆开看,其实就四步。

第一步,生成短码。常见做法有两种。一种是哈希法:对原始URL做MD5或SHA256运算,截取部分字符,遇到冲突就想办法去重。另一种是自增ID法:数据库每插入一条记录就分配一个自增ID,再把这个数字转成62进制——也就是用 a-z、A-Z、0-9 这62个字符来表示。举个例子,ID=12345 转成62进制就是 "7Xd"。自增法天然不会重复,哈希法则不暴露生成顺序,各有各的适用场景。

第二步,存储映射关系。短码和原始URL的对应关系得持久化下来,一张表就能搞定:



CREATE TABLE short_urls (
short_code VARCHAR(10) PRIMARY KEY,
original_url TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP
);


留意 expires_at 这个字段,后面做有效期控制全靠它。

第三步,重定向。用户访问 http://short.ly/7Xd 这样的短链时,服务器拿着 "7Xd" 去数据库查出原始URL,返回一个302状态码,浏览器收到后自动跳转。整个过程对用户完全透明,通常几十毫秒内就完成了。

到这里,一个能用的短链服务已经成型。第四步做的则是锦上添花:记录每次访问的IP、时间和User-Agent,就有了基础的点击统计;给短链加个密码,或者按地域限制访问,就能控制谁能看到内容;用Redis把热门短链的映射关系缓存起来,数据库的压力能减轻一大截。

不想自己造轮子的话,现成的工具也不少,只是各自的脾气不太一样。快缩短网址走的是免费路线,自带访问统计,还支持团队协作,适合营销跟踪、活动管理这类需要盯数据的场景。TinyURL 的特点是完全免费、无需注册,粘贴链接就出结果,临时用一下很顺手。Rebrandly 主打自定义域名和品牌管理,企业想让短链带上自家品牌名时会选它。Firebase 的动态链接则是另一个物种:它能识别用户有没有安装App,没装的引导去应用商店,装了的直接打开对应页面,做移动端深度链接基本绕不开它。

当然,如果你就是想自己动手写一个,核心逻辑用Python加Flask,几十行就能跑起来:

import hashlib
import base64
from flask import Flask, redirect, request

app = Flask(__name__)

<h1>模拟数据库(生产环境用Redis/MySQL)</h1>
url_db = {}

def generate_short_code(url):
# 方法1:哈希算法(加盐防碰撞)
hash_object = hashlib.sha256((url + "SALT").encode())
hex_dig = hash_object.hexdigest()
short_code = base64.urlsafe_b64encode(hex_dig[:6].encode()).decode()[:8]

<h1>方法2:自增ID(需线程安全处理)</h1>
# current_id = get_next_id_from_db()
# return base62_encode(current_id)

return short_code

@app.route('/shorten')
def shorten_url():
original_url = request.args.get('url')
if not original_url:
return "URL参数缺失", 400

<h1>生成短码(带碰撞检测)</h1>
short_code = generate_short_code(original_url)
while short_code in url_db:
short_code = generate_short_code(original_url + str(len(url_db)))

url_db[short_code] = original_url
return f"http://your-domain.com/{short_code}"

<img src="/uploads/20251015/33.png?t=1977421194" alt="" class="img-fluid" />

@app.route('/<short_code>')
def redirect_to_original(short_code):
original_url = url_db.get(short_code)
if original_url:
return redirect(original_url, code=302)
return "链接不存在", 404

<img src="/uploads/20251015/17.png?t=1863173075" alt="" class="img-fluid" />

if __name__ == '__main__':
app.run(debug=True)


这段代码演示了最基本的生成和跳转逻辑:加盐哈希生成短码,碰撞了就换一种输入重新生成,直到不冲突为止。生产环境里,url_db 这个字典自然要换成真正的数据库。

不过,真要把这样的服务推到线上,还有几个绕不开的坎。哈希碰撞在低并发下可以靠循环重试解决,数据量大了以后,用布隆过滤器做预检会高效得多。单机Redis扛不住的时候,映射关系得交给Redis Cluster做分布式存储,MySQL退居二线负责归档。短链服务天生暴露在公网,是DDoS攻击的热门目标,令牌桶、漏桶这类限流算法必须安排上。最后,把重定向服务部署到CDN边缘节点,全球用户的跳转都能快起来。

一套生产级架构大致长这样:用户请求先过CDN,再到负载均衡,后面是Flask服务集群,集群读写Redis Cluster,MySQL只做归档存储。

从原理到实现再到部署,链接缩短这件事本身并不复杂,难点全在细节和规模上。把这套逻辑想清楚了,不管用别人的工具还是自己造一个,心里都有底。