仿造 Kutt 项目的功能,使用 Go Fiber + SurrealDB 实现的 URL 短链接服务。
本项目使用 MiniMax 与 MiMo 系列模型生成的代码
- 后端: Go 1.25 + Fiber v3 + SurrealDB + Valkey
- 前端: SvelteKit + Svelte 5 (Runes 模式) + TailwindCSS 4 + Bun
- 日志:
log/slogJSON 结构化输出 - 容器: Docker (多阶段构建)
- URL 缩短 - 支持自定义短链接名称
- 用户系统 - 注册/登录,JWT + Refresh Token 双 token 认证
- 验证码 - 基于 base64captcha 的登录/注册验证
- 密码找回 - SMTP 邮件重置密码流程
- 链接管理 - 创建、编辑、删除、批量操作、查看统计
- API 密钥 - 支持 API 方式创建链接
- 访问统计 - 点击量、地理位置、设备类型、浏览器分析
- 密码保护 - 支持为短链接设置访问密码
- 举报系统 - 用户可举报恶意链接
- 管理后台 - 管理员可管理用户和链接,支持批量操作
- 限流保护 - 基于 Redis 的请求限流 (内存降级)
- Token 撤销 - 登出/改密自动撤销旧 token
- 安装引导 - 首次访问自动引导创建管理员 + 初始化数据库
- 结构化日志 - slog JSON 输出,支持日志级别配置
- 安全头 - CSP、HSTS、X-Frame-Options 等
- MCP 支持 - Model Context Protocol 工具调用
podman-compose up -d- 启动 SurrealDB:
podman run -p 8000:8000 surrealdb/surrealdb:v3 start --user root --pass root- 复制环境配置:
cp .env.example .env
# 编辑 .env,至少设置 JWT_SECRET (≥32字符) 和非 root 的 SurrealDB 凭据- 运行后端:
go run ./cmd/server- 访问 http://localhost:3000/setup 完成首次安装(创建管理员账号,自动初始化数据库表)
cd web
bun install
bun run dev前端运行在 http://localhost:5173,自动代理 /api 和 /u/:id 请求到后端 :3000。
cd web && bun run check| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 健康检查 (DB + Redis) |
| POST | /api/v1/shorten | 创建短链接 (可选 JWT) |
| GET | /api/v1/info/:shortURL | 获取链接信息 |
| POST | /api/v1/verify/:shortURL | 验证链接密码 |
| POST | /api/v1/report | 举报链接 |
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/auth/status | 检查是否已安装 (返回 has_users) |
| POST | /api/v1/auth/setup | 首次安装,创建管理员 |
| POST | /api/v1/auth/register | 用户注册 (需验证码) |
| POST | /api/v1/auth/login | 用户登录 (需验证码) |
| POST | /api/v1/auth/refresh | 刷新 access token |
| POST | /api/v1/auth/logout | 登出 (JWT 黑名单) |
| GET | /api/v1/auth/captcha | 获取验证码图片 |
| POST | /api/v1/auth/reset-password | 请求密码重置 |
| POST | /api/v1/auth/new-password | 确认密码重置 |
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/user/me | 获取当前用户 |
| PUT | /api/v1/user/me | 修改密码 |
| POST | /api/v1/user/apikey | 生成 API 密钥 |
| POST | /api/v1/user/delete | 删除账号 |
| GET | /api/v1/urls | 获取用户链接列表 |
| GET | /api/v1/urls/:id | 获取链接详情 |
| PUT | /api/v1/urls/:id | 更新链接 |
| DELETE | /api/v1/urls/:id | 删除链接 |
| GET | /api/v1/urls/:id/stats | 获取统计 |
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/admin/users | 用户列表 |
| PUT | /api/v1/admin/users/:id/ban | 封禁用户 |
| PUT | /api/v1/admin/users/:id/unban | 解封用户 |
| DELETE | /api/v1/admin/users/:id | 删除用户 |
| GET | /api/v1/admin/urls | 所有链接列表 |
| PUT | /api/v1/admin/urls/:id/ban | 封禁链接 |
| PUT | /api/v1/admin/urls/:id/disable | 禁用链接 |
| DELETE | /api/v1/admin/urls/:id | 删除链接 |
| POST | /api/v1/admin/urls/batch | 批量操作 (delete/disable/ban) |
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /mcp/v1 | MCP JSON-RPC 端点 (可选 JWT) |
MCP 协议版本 2025-11-25,提供 shorten_url 工具:
// tools/list
{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}
// tools/call
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {
"name": "shorten_url",
"arguments": {"url": "https://example.com", "custom_code": "abc", "description": "test"}
}}| 变量 | 默认值 | 说明 |
|---|---|---|
| PORT | 3000 | 服务端口 |
| DEFAULT_DOMAIN | localhost:3000 | 默认域名 |
| LINK_LENGTH | 6 | 短链接长度 |
| LOG_LEVEL | info | 日志级别 (debug/info/warn/error) |
| SURREALDB_URL | ws://localhost:8000 | SurrealDB 地址 |
| SURREALDB_USER | root | SurrealDB 用户名 |
| SURREALDB_PASSWORD | root | SurrealDB 密码 |
| SURREALDB_DATABASE | shorty | 数据库名 |
| JWT_SECRET | - | JWT 密钥 (≥32 字符,必须设置) |
| RATE_LIMIT_ENABLED | true | 启用限流 |
| RATE_LIMIT_PER_MINUTE | 60 | 每分钟请求限制 |
| DISALLOW_REGISTRATION | true | 禁止用户注册 |
| DISALLOW_ANONYMOUS_LINKS | false | 禁止匿名创建链接 |
| REDIS_URL | - | Redis 地址 (可选) |
| MAIL_SMTP_HOST | - | SMTP 服务器 (可选) |
| MAIL_SMTP_PORT | 587 | SMTP 端口 |
| MAIL_SMTP_USER | - | SMTP 用户名 |
| MAIL_SMTP_PASSWORD | - | SMTP 密码 |
| MAIL_FROM | noreply@example.com | 发件人地址 |
本服务监听纯 HTTP,生产环境必须在反向代理后运行,由反向代理处理 TLS 终止。
推荐 Nginx 配置:
server {
listen 80;
listen 443 http2;
server_name your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Docker 构建:
docker build -t shorty .
docker run -p 3000:3000 --env-file .env shortyshorty/
├── cmd/server/main.go # 后端入口
├── internal/
│ ├── config/ # 配置加载 + 启动校验
│ ├── handlers/ # HTTP 处理器
│ ├── services/ # 业务逻辑
│ ├── repository/ # 接口 + SurrealDB 实现
│ ├── middleware/ # 认证、限流、安全头、访问日志
│ ├── models/ # 数据模型
│ ├── schema/ # 嵌入式 DB schema (go:embed)
│ ├── cache/ # Redis 客户端
│ ├── captcha/ # 验证码管理
│ ├── mail/ # SMTP 邮件发送
│ ├── logger/ # slog 初始化
│ ├── routes/ # 路由配置 + DI
│ └── utils/ # 工具函数
├── pkg/errors/ # 错误类型
├── tasks/ # Asynq 后台任务
├── scripts/
│ ├── init-db.surql # 手动 DB 初始化
│ └── migrations/ # 迁移文件
├── web/ # SvelteKit 前端
│ ├── src/lib/api/ # API 客户端
│ ├── src/lib/components/ # UI 组件
│ ├── src/lib/stores/ # 状态管理
│ └── src/routes/ # 页面路由
├── Dockerfile
├── podman-compose.yml
└── Justfile # 开发命令