自建短链接服务:用Cloudflare Workers搭一个,比Bitly靠谱

先看效果

你搭建好了之后:

原始链接:https://navbox.com.cn/project/cloudflare-short-url/
短链接:   https://go.navbox.cn/abc123

点击短链接 → 302跳转 → 自动记录访问次数、IP、浏览器、来源。

全免费。不需要VPS,不需要数据库,不需要维护。

为什么自建

Bitly、TinyURL 这些用起来是方便。但:

  • 免费版有链接数量限制
  • 你不知道哪天服务就关了
  • 数据在别人手里
  • 自定义域名要付费

Cloudflare Workers 免费版每天10万次请求,对于个人站长来说根本用不完。

架构

用户访问短链接 → Cloudflare Workers → 查询KV存储 → 302跳转 → 记录访问日志
                                                ↓
                                            Cloudflare KV
                                            (key: 短码, value: 原始URL)

Cloudflare KV 是全球分布的键值数据库。读写都在边缘节点完成,延迟极低。

第一步:准备工作

你需要:

  1. 一个 Cloudflare 账号(免费)
  2. 一个域名(在 Cloudflare 上管理)

假设你的域名是 navbox.cn,准备用一个子域名 go.navbox.cn 来跑短链接服务。

先添加 DNS 记录:

类型: CNAME
名称: go
目标: 随便一个有效地址(Worker部署时会自动覆盖)
代理状态: 开启(橙色云朵)

第二步:创建 Worker

打开 Cloudflare Dashboard → Workers & Pages → 创建 Worker。

粘贴下面的代码:

// 短链接服务主程序
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

// KV 命名空间(部署时绑定)
// 在 wrangler.toml 中配置,或者在 Dashboard 中绑定

async function handleRequest(request) {
  const url = new URL(request.url)
  const shortCode = url.pathname.replace('/', '')

  // 首页显示使用说明
  if (!shortCode) {
    return new Response(renderHomePage(), {
      headers: { 'Content-Type': 'text/html; charset=utf-8' }
    })
  }

  // API:创建短链接
  if (url.pathname === '/api/create' && request.method === 'POST') {
    return handleCreate(request)
  }

  // 查询短链接并跳转
  const originalUrl = await SHORT_URL_KV.get(shortCode)
  if (!originalUrl) {
    return new Response('链接不存在或已过期', { status: 404 })
  }

  // 异步记录访问日志(不阻塞跳转)
  recordVisit(shortCode, request)

  // 302 跳转
  return Response.redirect(originalUrl, 302)
}

// 创建短链接
async function handleCreate(request) {
  const { url: targetUrl, customCode } = await request.json()

  if (!targetUrl) {
    return new Response(JSON.stringify({ error: '缺少URL参数' }), {
      status: 400,
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // 生成短码(6位随机字符串)
  const code = customCode || generateShortCode(6)

  // 检查是否已存在
  const existing = await SHORT_URL_KV.get(code)
  if (existing) {
    return new Response(JSON.stringify({ error: '短码已存在,换个试试' }), {
      status: 409,
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // 存入 KV
  await SHORT_URL_KV.put(code, targetUrl, {
    expirationTtl: 0  // 永不过期
  })

  return new Response(JSON.stringify({
    shortCode: code,
    shortUrl: `https://go.navbox.cn/${code}`,
    originalUrl: targetUrl
  }), {
    headers: { 'Content-Type': 'application/json' }
  })
}

// 记录访问
async function recordVisit(shortCode, request) {
  const cf = request.cf || {}
  const visit = {
    timestamp: new Date().toISOString(),
    ip: request.headers.get('CF-Connecting-IP') || 'unknown',
    country: cf.country || 'unknown',
    ua: request.headers.get('User-Agent') || 'unknown',
    referer: request.headers.get('Referer') || 'direct'
  }

  // 用 KV 存储访问记录(每天一份)
  const today = new Date().toISOString().split('T')[0]
  const logKey = `log:${shortCode}:${today}`
  const existingLogs = await SHORT_URL_KV.get(logKey)
  const logs = existingLogs ? JSON.parse(existingLogs) : []
  logs.push(visit)

  // 最多存最近1000条
  if (logs.length > 1000) logs.shift()
  await SHORT_URL_KV.put(logKey, JSON.stringify(logs))

  // 更新计数器
  const countKey = `count:${shortCode}`
  const currentCount = parseInt(await SHORT_URL_KV.get(countKey) || '0')
  await SHORT_URL_KV.put(countKey, String(currentCount + 1))
}

// 生成随机短码
function generateShortCode(length) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length))
  }
  return result
}

// 首页
function renderHomePage() {
  return `<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>短链接服务</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 50px auto; padding: 0 20px; }
    input, button { font-size: 16px; padding: 10px; width: 100%; box-sizing: border-box; margin: 5px 0; }
    .result { margin-top: 20px; padding: 15px; background: #f0fdf4; border-radius: 8px; display: none; }
    .error { background: #fef2f2; }
  </style>
</head>
<body>
  <h1>🔗 短链接生成器</h1>
  <input type="url" id="urlInput" placeholder="粘贴长链接..." />
  <input type="text" id="customInput" placeholder="自定义后缀(选填,留空自动生成)" />
  <button onclick="createLink()">生成短链接</button>
  <div id="result" class="result"></div>

  <script>
    async function createLink() {
      const url = document.getElementById('urlInput').value
      const custom = document.getElementById('customInput').value
      const result = document.getElementById('result')
      if (!url) { alert('请输入URL'); return }

      const res = await fetch('/api/create', {
        method: 'POST',
        body: JSON.stringify({ url, customCode: custom || undefined })
      })
      const data = await res.json()
      result.style.display = 'block'
      if (data.shortUrl) {
        result.className = 'result'
        result.innerHTML = '✅ 生成成功!<br><br>' +
          '<strong>短链接:</strong><a href="' + data.shortUrl + '" target="_blank">' + data.shortUrl + '</a><br>' +
          '<strong>原始链接:</strong>' + data.originalUrl
      } else {
        result.className = 'result error'
        result.innerHTML = '❌ ' + (data.error || '生成失败')
      }
    }
  </script>
</body>
</html>`
}

第三步:配置 KV + 绑定

在 Cloudflare Dashboard 左侧找到 Workers & Pages → KV

  1. 点击「创建命名空间」,名称填 SHORT_URL_KV
  2. 回到 Worker 编辑页面 →「设置」→「变量」
  3. 在「KV 命名空间绑定」中点击「添加绑定」
  4. 变量名称填 SHORT_URL_KV,选择刚才创建的 KV 命名空间
  5. 点击保存并部署

第四步:绑定自定义域名

在 Worker 详情页 →「触发器」→「自定义域名」:

域名: go.navbox.cn

Cloudflare 会自动配置 DNS 和 SSL 证书。等几分钟就能生效。

第五步:测试

打开 https://go.navbox.cn,应该能看到生成器页面。

输入一个长链接测试:

原始链接: https://github.com/cloudflare/workers-sdk
短链接:   https://go.navbox.cn/aB3xK9

打开短链接 → 自动跳转到 GitHub。

第六步:用 curl 批量生成(适合脚本)

# 创建短链接
curl -X POST https://go.navbox.cn/api/create \
  -H "Content-Type: application/json" \
  -d '{"url": "https://navbox.com.cn/project/cloudflare-short-url/"}'

# 返回
{"shortCode":"xYz789","shortUrl":"https://go.navbox.cn/xYz789","originalUrl":"https://navbox.com.cn/project/cloudflare-short-url/"}

# 自定义后缀
curl -X POST https://go.navbox.cn/api/create \
  -H "Content-Type: application/json" \
  -d '{"url": "https://navbox.com.cn", "customCode": "navbox"}'
# 返回: https://go.navbox.cn/navbox

查看统计数据

访问计数存到了 KV 里。你可以通过 Worker 加一个统计 API:

// 在 handleRequest 中增加
if (url.pathname === '/api/stats/' + shortCode) {
  const count = await SHORT_URL_KV.get('count:' + shortCode) || '0'
  const today = new Date().toISOString().split('T')[0]
  const logs = await SHORT_URL_KV.get('log:' + shortCode + ':' + today)
  return new Response(JSON.stringify({
    shortCode,
    totalClicks: parseInt(count),
    todayVisits: logs ? JSON.parse(logs).length : 0,
    todayDetail: logs ? JSON.parse(logs) : []
  }), {
    headers: { 'Content-Type': 'application/json' }
  })
}
curl https://go.navbox.cn/api/stats/aB3xK9

# 返回
{
  "shortCode": "aB3xK9",
  "totalClicks": 58,
  "todayVisits": 12,
  "todayDetail": [
    {"timestamp": "2026-06-05T08:30:00Z", "ip": "xxx", "country": "CN", "ua": "Mozilla/5.0 ...", "referer": "direct"}
  ]
}

用 wrangler 部署(高级)

上面是在 Dashboard 里操作的。如果你想用命令行:

# 安装 wrangler
npm install -g wrangler

# 登录
wrangler login

# 初始化项目
mkdir my-short-url && cd my-short-url
wrangler init

# 粘贴上面的代码到 src/index.ts

# 配置 wrangler.toml

wrangler.toml 内容:

name = "short-url"
main = "src/index.ts"
compatibility_date = "2026-06-01"

[[kv_namespaces]]
binding = "SHORT_URL_KV"
id = "你的KV命名空间ID"

[env.production]
routes = [
  { pattern = "go.navbox.cn", custom_domain = true }
]
# 部署
wrangler deploy

优化方向

  1. 加密码保护:某些短链接只允许指定的人访问,加个密码验证
// 创建时传密码
await SHORT_URL_KV.put(code + ':password', hashedPassword)

// 访问时校验
if (needPassword) {
  // 返回一个密码输入页面
}
  1. 过期时间:活动链接有时间限制
// 7天后自动过期
await SHORT_URL_KV.put(code, url, { expirationTtl: 604800 })
  1. 二维码生成:短链接自动生成二维码,用 api.qrserver.com 或自己部署
// 在结果页面加上
<img src="https://api.qrserver.com/v1/create-qr-code/?data=${shortUrl}&size=200x200" />
  1. 批量导入:从 CSV 批量创建短链接
# 用脚本批量处理
cat links.csv | while IFS=, read url slug; do
  curl -X POST https://go.navbox.cn/api/create \
    -H "Content-Type: application/json" \
    -d "{\"url\": \"$url\", \"customCode\": \"$slug\"}"
done
  1. Analytics 面板:用 D1 数据库(Cloudflare 的关系型数据库)替代 KV 做日志,支持时间范围查询和图表展示

总结

这个短链接服务:

  • ✅ 完全免费(每月10万次请求)
  • ✅ 全球加速(Cloudflare 边缘网络)
  • ✅ 自带统计
  • ✅ 支持自定义域名
  • ✅ 有 API 可以对接其他工具

整个搭建过程不超过10分钟。不需要服务器、不需要数据库、不需要运维。

如果你需要更高级的功能——比如团队协作、AB测试、多域名支持——可以考虑用 Dub.co 或者自己基于这个 Worker 代码继续扩展。

代码就这么多。复制粘贴,改一下域名,跑起来。

这篇文章对你有帮助吗?