在日常开发中,我们经常会遇到分享长链接、管理短链、统计点击量的需求。你也许已经习惯使用 bit.ly、t.cn 这类短链接服务,但你是否想过:
👉 自己写一个短链接生成器,其实只需要不到 150 行 Go 代码!
本文带你揭开短链接服务的神秘面纱,构建一个极简但结构清晰的短链接服务。你不仅能学会如何处理路由、表单、随机短链生成和跳转,还能将它继续扩展为可持久化、可统计、可容器化的完整系统。
出于极简风考虑今天选用了echo框架。
🚀为什么选择 Go 来写短链接?
短链接服务的特点是:
- 高频请求
- 高性能要求
- 架构简单但扩展性强
而 Go 正好具备:
- 高并发、高性能的原生优势
- 简单易读的语法
- 强大且完善的标准库
- 易部署、易容器化
一个轻量级的短链接服务,用 Go 来写再合适不过。
⭐功能概述
我们将构建的短链接服务包含:
- 输入任意 URL,自动生成短链
- 访问短链 → 301 跳转原始链接
- 首页展示所有短链
- 基于 Echo 框架快速构建
结构清晰,扩展友好。
🧩架构设计
整个系统由 3 个核心 Handler 组成:
IndexHandler → 首页:输入框 + 链接列表
SubmitHandler → 创建短链
RedirectHandler → 访问短链并跳转
底层使用内存 Map 存储,可轻松替换为 Redis/PostgreSQL。
📁项目目录结构建议
采用轻量但可扩展的目录结构:
url-shortener/
├── main.go
├── handler/
│ ├── index.go
│ ├── submit.go
│ └── redirect.go
├── storage/
│ └── memory.go
└── util/
└── random.go
比常见的“一个文件写到底”更适合后续扩展。
🧑💻 核心代码
🔧随机短链生成
func GenerateRandomString(n int) string {
seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
var result []byte
for i := 0; i < n; i++ {
index := seededRand.Intn(len(charset))
result = append(result, charset[index])
}
return string(result)
}
采用 Base62 字符集,短链随机分布更均匀。
📝创建短链(SubmitHandler)
func SubmitHandler(c echo.Context) error {
url := c.FormValue("url")
if url == "" {
return c.String(http.StatusBadRequest, "url is required")
}
// 自动补全协议
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "https://" + url
}
// 生成短链 ID
id := util.GenerateRandomString(8)
// 保存
storage.LinkMap[id] = &storage.Link{
Id: id,
Url: url,
}
return c.Redirect(http.StatusSeeOther, "/")
}
要点:
- 自动补全
https:// - 生成随机短链 ID
- 写入存储
- 使用 303 重定向回首页
🔀短链跳转(RedirectHandler)
func RedirectHandler(c echo.Context) error {
id := c.Param("id")
link, ok := storage.LinkMap[id]
if !ok {
return c.String(http.StatusNotFound, "short link not found")
}
return c.Redirect(http.StatusMovedPermanently, link.Url)
}
采用 301 永久重定向,利于浏览器与 CDN 缓存。
🏠首页展示(IndexHandler)
func IndexHandler(c echo.Context) error {
html := `
<h1>Go 短链接服务</h1>
<form method="POST" action="/submit">
<input name="url" placeholder="请输入一个 URL" style="width: 300px;" />
<button type="submit">生成短链</button>
</form>
<hr>
<h3>已生成的短链:</h3>
<ul>
`
for _, link := range storage.LinkMap {
html += fmt.Sprintf("<li><a href='/%s'>/%s</a> → %s</li>",
link.Id, link.Id, link.Url)
}
html += "</ul>"
return c.HTML(http.StatusOK, html)
}
轻量级 HTML,可替换为模板引擎。
🔮扩展方向
如果你想将其做大做强,你可以无限的发挥自己的想象,无限的扩展。
1. 持久化:Redis/PostgreSQL
解决重启后数据丢失。
2. 点击统计与分析(日志管理,运营分析)
记录 PV/UV、来源、地理位置等。
3. 自定义短链(slug)
例如 /go-best-practice。
4. Docker 化部署
轻松上线,镜像可做到 10MB 级。
一个原型项目,也能持续成长为生产级服务,只要你肯想,就没有代码做不到的,程序员动起手来,没有什么不可能。
📥示例源码(可直接运行)
已准备可运行示例项目:
- (国际)GitHub:
👉 github.com/louis-xie-p… - (国内)Gitee:
👉 gitee.com/louis_xie/u…