本教程将指导您使用Cloudflare Workers和Workers KV搭建一个功能完整的短网址服务。该服务支持创建短链接、自动检测微信浏览器并显示提示,使用KV存储短链映射,免费额度足够个人使用。
功能特点
- ✅ 支持创建短链接(如
/abc123跳转到目标URL) - ✅ 自动检测是否在微信浏览器中打开
- ✅ 如果在微信中打开,则显示提示:"请复制到浏览器打开"
- ✅ 使用 Cloudflare KV 存储映射关系(免费额度足够个人使用)
- ✅ 提供 Web 界面用于生成短链
- ✅ 防止重复提交相同长链接(基于 SHA-1 哈希去重)
- ✅ 阻止用户输入自身短链接(避免循环)
- ✅ 防止短链重复生成(相同URL生成相同短码)
- ✅ 友好的404错误页面
- ✅ 移动端友好的响应式设计
准备工作
第一步:注册Cloudflare账号
访问 Cloudflare官网 注册账号。
第二步:创建Worker
- 登录Cloudflare控制台
- 进入Workers & Pages
- 点击"创建应用程序"
- 选择"创建Worker"
- 命名Worker(例如:
url-shortener) - 点击"部署"
第三步:创建KV命名空间
- 在Worker详情页面,选择"设置"标签
- 点击"变量" → "KV命名空间绑定"
- 点击"添加绑定"
- 变量名称输入:
URL_MAPPINGS - 点击"创建新的KV命名空间"
- 命名空间名称输入:
URL_MAPPINGS - 点击"保存"
第四步:将KV绑定到Worker
- 在变量绑定部分,选择刚才创建的
URL_MAPPINGS命名空间 - 点击"保存并部署"
核心代码实现
配置文件
const SHORT_CODE_LENGTH = 6; // 短码长度
工具函数
检测被禁用的UA
function isBannedUA(ua) {
ua = ua.toLowerCase();
return /micromessenger/i.test(ua) || /weibo/.test(ua) || /qq\//.test(ua);
}
SHA-1哈希生成
async function sha1(str) {
const encoder = new TextEncoder();
const data = encoder.encode(str);
const hashBuffer = await crypto.subtle.digest('SHA-1', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
生成短码
function generateShortCode() {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < SHORT_CODE_LENGTH; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
页面模板
404错误页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>短链接不存在</title>
<!-- 样式和脚本 -->
</head>
<body>
<div class="container">
<div class="error-icon">❌</div>
<h1>短链接不存在</h1>
<p>您访问的短链接已失效或不存在</p>
<button class="btn" onclick="window.location.href='/'">返回主页</button>
</div>
</body>
</html>
微信拦截页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>提示</title>
<!-- 样式和脚本 -->
</head>
<body>
<div class="card">
<h2>⚠️无法在当前应用中打开</h2>
<p>点击右上角菜单</p>
<p>选择 <span class="highlight">"在浏览器中打开"</span></p>
</div>
</body>
</html>
主页(短链接生成器)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>短链接生成器</title>
<!-- 样式和脚本 -->
</head>
<body>
<div class="container">
<h1>🔗 短链接生成器</h1>
<div class="card">
<form id="shorten-form">
<input type="url" id="url-input" placeholder="请输入完整网址(如 https://example.com)" required />
<button type="submit">生成短链接</button>
</form>
<div class="result"></div>
</div>
<!-- 友链部分 -->
<p class="links">友链:...</p>
</div>
<script>
// 客户端JavaScript代码
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('shorten-form');
// 事件委托处理复制按钮
document.addEventListener('click', (e) => {
if (e.target.classList.contains('copy-btn')) {
const shortUrl = e.target.closest('.result').querySelector('a').href;
copyLink(shortUrl);
}
});
// 表单提交处理
form.addEventListener('submit', async (e) => {
e.preventDefault();
// 客户端微信检测
if (/MicroMessenger/i.test(navigator.userAgent)) {
alert('请在浏览器中打开,不要在微信中使用');
return;
}
// 表单数据处理
// ...
});
});
</script>
</body>
</html>
请求处理器
async function handleRequest(request) {
const url = new URL(request.url);
const path = url.pathname;
const userAgent = request.headers.get('User-Agent') || '';
const inWechat = isBannedUA(userAgent);
// 1. 处理微信环境
if (inWechat && (path === '/' || path.startsWith('/'))) {
return new Response(WECHAT_BLOCK_PAGE, {
headers: { 'Content-Type': 'text/html; charset=utf-8' }
});
}
// 2. 处理短链接跳转
const shortCodeMatch = path.match(/^\/([a-zA-Z0-9]{6})$/);
if (shortCodeMatch) {
const shortCode = shortCodeMatch[1];
const targetUrl = await LINKS.get(shortCode);
if (targetUrl) {
return Response.redirect(targetUrl, 302);
} else {
return new Response(NOT_FOUND_PAGE, {
headers: { 'Content-Type': 'text/html; charset=utf-8' }
});
}
}
// 3. 处理主页请求
if (request.method === 'GET' && path === '/') {
return new Response(homePage(), {
headers: { 'Content-Type': 'text/html; charset=utf-8' }
});
}
// 4. 处理短链接生成请求
if (request.method === 'POST' && path === '/') {
try {
// 表单数据处理
const formData = await request.formData();
let targetUrl = formData.get('url')?.trim();
// URL验证和规范化
if (!targetUrl) throw new Error('请输入网址');
if (!/^https?:\/\//i.test(targetUrl)) {
targetUrl = 'https://' + targetUrl;
}
const normalizedUrl = targetUrl.replace(/\/$/, '');
// 防止短链接循环
try {
const inputUrl = new URL(normalizedUrl);
const currentDomain = new URL(url.origin);
if (inputUrl.hostname === currentDomain.hostname &&
inputUrl.pathname.length === 7 &&
inputUrl.pathname[0] === '/' &&
/^[a-zA-Z0-9]{6}$/.test(inputUrl.pathname.substring(1))) {
return new Response('输入的URL是短链接,请输入长链接', {
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}
} catch (e) {
throw new Error('网址格式无效');
}
// 检查URL是否已存在
const urlHash = (await sha1(normalizedUrl)).substring(0, 12);
const hashKey = `hash:${urlHash}`;
const existingCode = await LINKS.get(hashKey);
if (existingCode) {
return new Response(`${url.origin}/${existingCode}`, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}
// 生成新短码
const shortCode = generateShortCode();
const fullShortUrl = `${url.origin}/${shortCode}`;
// 存储到KV
await Promise.all([
LINKS.put(shortCode, normalizedUrl),
LINKS.put(hashKey, shortCode)
]);
return new Response(fullShortUrl, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
} catch (e) {
console.error('短链生成失败:', e.message);
return new Response(`❌ ${e.message}`, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
status: 400
});
}
}
// 5. 处理404
if (path !== '/' && !shortCodeMatch) {
return new Response(NOT_FOUND_PAGE, {
headers: { 'Content-Type': 'text/html; charset=utf-8' }
});
}
}
Worker入口点
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
部署和使用
部署步骤
- 将完整代码复制到Worker编辑器中
- 点击"保存并部署"
- 访问您的Worker域名(如:
your-worker.workers.dev)
使用方法
- 访问短网址服务主页
- 在输入框中输入要缩短的完整URL
- 点击"生成短链接"按钮
- 复制生成的短链接(格式:
your-domain.com/abc123) - 分享短链接,用户访问时会自动跳转到原始URL
功能说明
| 功能 | 实现方式 |
|---|---|
| 短链生成 | POST / 提交 url 参数,返回 https://your-worker.example/abc123 |
| 跳转 | 访问 /abc123 → 302 重定向到原始 URL |
| 微信拦截 | 检测 UA 中包含 MicroMessenger、weibo、QQ/,返回提示页 |
| 防重复 | 对规范化 URL 计算 SHA-1 哈希前 12 位,存为 hash:xxx,下次直接返回已有短码 |
| 防自环 | 禁止用户提交形如 https://your-worker.example/xxxxxx 的短链接 |
| 404 页面 | 所有无效路径均返回友好提示 |
安全与隐私说明
- 本服务 不收集任何用户数据
- 不使用 Cookie、LocalStorage(除临时复制外)
- 所有逻辑运行在 Cloudflare 边缘节点
- KV 存储仅包含:
短码 → 长链接和哈希 → 短码映射
技术特性
1. 短码生成策略
- 使用6位字符(大小写字母+数字)共62^6≈568亿种组合
- 相同URL始终生成相同短码,避免重复存储
2. 性能优化
- KV存储读写操作快速响应
- 客户端和服务端双重微信检测
- 响应式设计适配各种设备
3. 安全性
- 输入URL验证和规范化
- 防止短链接循环引用
- 自动补全HTTPS协议
4. 用户体验
- 简洁直观的操作界面
- 一键复制短链接功能
- 友好的错误提示页面
- 微信环境下的明确指引
注意事项
-
免费额度限制:Cloudflare Workers免费套餐包括:
- 每天10万次请求
- KV存储:100,000次读取/天,1,000次写入/天
- 存储空间:1GB
-
域名绑定:可以将自定义域名绑定到Worker,通过"触发器" → "自定义域"设置
-
监控和统计:可以在Cloudflare控制台查看Worker的请求统计和错误日志
-
备份建议:定期导出KV中的数据作为备份
故障排除
常见问题
- Worker无法访问:检查Worker是否已部署,网络连接是否正常
- 短链接不跳转:检查KV绑定是否正确,短码是否已存储
- 微信检测失效:检查User-Agent检测逻辑是否被微信更新影响
- 生成失败:检查输入URL格式,确保不是短链接本身
调试方法
- 使用浏览器开发者工具查看网络请求
- 查看Worker控制台的错误日志
- 测试不同的User-Agent模拟不同环境
- 检查KV命名空间中的数据状态
扩展建议
- 添加统计功能:记录每个短链接的访问次数
- 设置过期时间:为短链接添加有效期
- 密码保护:为敏感链接添加访问密码
- 批量生成:支持一次生成多个短链接
- API接口:提供RESTful API供第三方调用
后续可扩展方向
- 添加 API Key 验证(防止滥用)
- 支持自定义短码(如
/github) - 添加点击统计(需额外 KV 或 D1)
- 集成密码保护短链
- 支持批量生成
总结
本教程详细介绍了如何使用Cloudflare Workers和Workers KV搭建一个完整的短网址服务。该方案具有部署简单、成本低廉、性能优越的特点,适合个人和小型项目使用。通过微信检测、重复URL检测、友好的用户界面等功能,提供了良好的用户体验。
这个短网址服务可以满足日常的链接缩短需求,同时具备良好的扩展性,可以根据需要进行功能增强和定制开发。
体验地址
原文地址短链:dwz.xuehuayu.cn/8GCWqt
完整代码短链:dwz.xuehuayu.cn/sWBnDP
原文地址链接·:www.xuehuayu.cn/article/c4c…
完整代码链接:www.xuehuayu.cn/article/288…